Size Cortex Code per-user limits from real usage¶
Tiered per-user CoCo quotas, daily limits, and alert-only team budgets, starting from conservative defaults and sized from your own ACCOUNT_USAGE.
| Stage | Operate |
| Topics | AI Observability, Cortex Code |
| Status | GA |
| Time to complete | 30min |
| Edition | Enterprise |
| Regions | Any region with Cortex Code and SNOWFLAKE_COCO_USAGE_HISTORY |
| Privileges | ACCOUNTADMIN for 01_setup.sql, the optional 05_account_backstop.sql (account parameters), and 99_teardown.sql; 02, 03, and 04 run as the COOKBOOK_* role |
| Related skills | cost-intelligence (bundled with Cortex Code) |
| Last verified | 2026-10-13 |
| Authors | Cal Jepson |
| Code | View all files or download coco-user-budget-sizing.zip, which includes this page as README.md. Teardown: sql/99_teardown.sql |
This recipe is a reference implementation: review the code and adapt it to your environment before production use.
Give every Cortex Code (CoCo) user room to work, stop runaway spend before it hits the bill, and know which numbers to pick. This recipe deploys tiered per-user quotas and an alert-only team budget with conservative starting limits, gives you the SQL to size those limits from your own account, and makes blocking a deliberate step you take once the numbers have been reviewed.
When to use this¶
- You are about to turn CoCo on and want sensible per-user limits in place from day one, before you have any usage history.
- You are rolling CoCo out beyond a pilot and need per-user limits that most people will never notice.
- You have a few heavy users and want them governed separately from everyone else.
- Finance wants alerts on team-level spend without anyone being blocked by them.
Not the right fit if you only need to report on CoCo spend after the fact. For that, start with AI usage and cost attribution.
How it works¶
This recipe owns the per-user quotas for CoCo. It builds on AI usage and cost attribution for reporting. Don’t also add the CORTEX CODE shared resource to that recipe’s quota: CoCo users would then sit under two independent quotas, each of which can block them.
Four ideas shape the setup:
- Two audiences, two quotas. CoCo spend is usually uneven: a few people who use it every day account for much of it. One limit can’t fit both groups. Tag power users with
USAGE_TIER = 'power'. A General quota covers everyone except that tag; a Power quota covers only that tag. In this recipe, a power user is anyone active on 15 or more of the last 30 days, which is a working pattern, not a spending level. - The monthly limit is the budget; the daily limit is the safety net. The daily limit sits well below the monthly one. For General users, 35 a day is under a quarter of the 150 monthly limit, so it catches a runaway loop or a mistake within hours, and one bad day can’t use up the month.
- Alert first, block deliberately. The first deployment only observes. Admins get summaries, and quotas record who would cross a limit, but nobody is blocked and, by default, no user gets emailed. You turn on user notices and blocking as separate, explicit steps once you have reviewed the numbers.
- Team budgets watch, quotas enforce. A budget scoped by a
COST_CENTERtag alerts when a team’s total CoCo spend crosses a threshold. It has no action attached, so it never blocks anyone.
Starting limits¶
These are conservative defaults to start with, not measured recommendations. Your own usage, measured by sql/02_size_your_limits.sql, is the evidence for adjusting them.
| Control | General | Power |
|---|---|---|
| Monthly quota (per user) | 150 | 1,500 |
| Daily limit inside the quota (per user) | 35 | 150 |
| Blocking at the limit | off until you turn it on | off until you turn it on |
| Account daily parameter (optional backstop, each surface) | 300 | 300 |
| Team budget | alert only | alert only |
Prerequisites¶
| Requirement | Notes |
|---|---|
| Enterprise edition or higher | Per-user quotas and budgets for shared resources require it. |
| ACCOUNTADMIN | To create the recipe role, grant the SNOWFLAKE.USAGE_VIEWER, QUOTA_CREATOR, and BUDGET_CREATOR database roles, tag users, and (optionally) set account parameters. |
| Verified admin email addresses | Admin summaries and team budget alerts go to these addresses. Set them in sql/03. |
| CoCo usage history (optional) | You need a few weeks of usage only to size limits from your own data. Without it, start with the defaults. |
Quickstart¶
snow sql -f sql/01_setup.sqlas ACCOUNTADMIN: role, warehouse, database, and tags.- If you already use CoCo,
snow sql -f sql/02_size_your_limits.sql: your percentiles, a back-test of the candidate limits, and suggested power users. Review and run the generatedALTER USER ... SET TAGstatements. Skip this step if you have no usage yet; everyone starts in the General quota. - Set
admin_emailsinsql/03_quotas_and_budget.sql, thensnow sql -f sql/03_quotas_and_budget.sql: quotas, team budget, scope, and alerts. - Wait 5 to 10 minutes for scope to propagate, then
snow sql -f sql/04_limits.sql: limits, with blocking off. - Optional:
snow sql -f sql/05_account_backstop.sqlas ACCOUNTADMIN, if you want an account-wide daily limit. Read Add the account-wide backstop first. - After two to four weeks of alerts, turn on enforcement.
Walkthrough¶
1. Measure your own usage¶
02_size_your_limits.sql creates one view, SIZING.USER_DAILY, over SNOWFLAKE.ACCOUNT_USAGE.SNOWFLAKE_COCO_USAGE_HISTORY, labels each user General or Power by active days, and returns the monthly and daily percentiles:
Size the limits from the results:
- Monthly limit: about 2 times the p99 for small groups (under 200 users), or about the p99.5 for large ones.
- Daily limit: about 3 to 4 times the daily p99 for General users, and about 1.5 to 2 times for Power users, whose usual day is already heavy. Keep it well below the monthly limit, at a quarter or less, so one runaway day can’t use up the month.
Then set the candidate values at the top of the script and rerun the back-test. Aim for under 1% of users blocked in a month.
2. Tag power users¶
The last query in 02 lists suggested power users and generates the statement for each:
Review the list before running it. Power is a working pattern, not a reward, so revisit it monthly. Tag team members with COST_CENTER the same way if you want team budget alerts.
3. Create the quotas and the team budget¶
03_quotas_and_budget.sql creates both quotas against the CORTEX CODE shared resource, sets scope, and adds the alerts:
notify_user defaults to FALSE, so admins get summaries but individual users get no email while you review the numbers. Set it to TRUE and rerun 03 when you want every CoCo user in scope to be told when they are projected to reach 80% of their limit and when they reach 100%.
The Power quota uses SET_USER_TAGS(..., 'UNION') with the same tag instead of EXCLUDE_USERS. The team budget uses SET_SPENDING_LIMIT, SET_USER_TAGS on COST_CENTER, and SET_NOTIFICATION_THRESHOLD(80), with no custom action, so it only alerts.
4. Set the limits¶
After scope has propagated, 04_limits.sql sets the limits with blocking off:
5. Turn on enforcement¶
Leave blocking off for the first two to four weeks. During that time, check who crosses a limit in the admin summaries and in Snowsight, and rerun the back-test in 02 against the new usage. When the share of users who would be blocked is acceptable, set block_enabled = TRUE in 04_limits.sql and rerun it. Blocked users are emailed unless you set notify_blocked = FALSE. To go back to alert only, set block_enabled = FALSE and rerun; blocked users are released within about 5 to 10 minutes.
6. Optional: add the account-wide backstop¶
05_account_backstop.sql is a separate, opt-in step because it changes account-level state. It backs up the current values, then sets the account-wide daily parameters, which apply to every user on each surface, including anyone a quota does not cover:
These parameters block as soon as they are set, whatever block_enabled says.
7. Extend it¶
The quotas, tags, and budget are a foundation to keep, not a test fixture. Add a team budget for each team by tagging its members with COST_CENTER and creating another budget like COCO_TEAM_BUDGET. Revisit the power-user list and the limits monthly with 02, and rerun 04 when they change.
Where to see it in Snowsight¶
Go to Admin » Cost management » Budgets. Quotas and budgets are listed together. Open a quota to see its enforcement breakdown (users near or over their limits) and per-user spend by day.
Verify¶
A tagged power user appears in the Power scope and not in the General scope. GET_CONFIG shows the limits you set. Until you turn on enforcement, GET_ACTIVE_BLOCKS_V2 returns no rows. The parameters stay at their original values unless you ran 05.
Gotchas¶
| Symptom | Cause | Fix |
|---|---|---|
| A newly tagged user is still in the wrong quota | Scope changes take 5 to 10 minutes; new tag assignments can take up to about 2 hours | Check GET_QUOTA_SCOPE before setting limits, and wait before rerunning 04. |
| A user is blocked earlier or later than the quota daily limit suggests | A quota’s daily cycle resets at 00:00 UTC; the account parameters use a rolling 24-hour window per surface | Keep the 05 backstop well above the quota daily limits so the two never compete. |
| A team budget alert arrives hours after the spend | Budgets refresh up to every 6.5 hours by default | Use budgets for alerts and quotas for enforcement, or call SET_REFRESH_TIER('TIER_1H') on the budget for hourly refresh at higher cost. |
02 shows no recent usage or a short tail | SNOWFLAKE_COCO_USAGE_HISTORY lags by up to an hour, and fewer than two weeks of data understates the tail | Size on at least two weeks, ideally 30 days. |
| Every user is blocked from CoCo | An account parameter was set to 0, which blocks all use (-1 means unlimited) | Rerun 05 with a positive backstop_daily, or restore with 99_teardown.sql. |
Users are blocked even though block_enabled = FALSE | 05 was run; the account parameters block independently of the quotas | Raise backstop_daily, or restore the originals with teardown. |
Teardown¶
Teardown drops the quotas and the budget, restores the original daily limit parameters if you ran 05, and drops the role, database, and warehouse. Dropping the database drops the USAGE_TIER and COST_CENTER tags, which removes their assignments from users. Use it to back out the recipe completely; if you are keeping per-user limits, extend the deployment instead.
Adapt this recipe¶
Keep these, so a customized version keeps the recipe’s security model:
- Least privilege:
ACCOUNTADMINonly for the scripts listed under Privileges; everything else runs as the recipe’s own role. - No grants to
PUBLIC. - Credentials: create keys, tokens, and secrets yourself, in a separate terminal, and read them from environment variables. Never put them in a script or give them to an agent.
- Dynamic SQL, if you add any, uses bind variables or an allowlist of identifiers, never text concatenated from user or model input.
Change these to fit your use case:
- Object names. Rename them in every script, including teardown, then check that teardown still removes everything.
- Roles, personas, and users: map them to your own, each granted no more than the recipe grants.
- Data: point the scripts at your tables instead of the sample data, then run Verify again.
- Models and warehouse sizes.
To have a coding agent adapt it:
Run it with a coding agent¶
Related skills¶
cost-intelligence(bundled): analyze CoCo and other AI spend, budgets, and quotas in your account.