# CommitOps > The ledger of every promise a company has made to a customer, joined to the work that satisfies it and the revenue that depends on it. Agents read and write it through an MCP server and an HTTP API, as principals, under the same rules as people. MCP server (streamable HTTP): https://commitops.ai/api/mcp HTTP API: POST https://commitops.ai/api/v1/tools/, JSON in and out OpenAPI 3.1: https://commitops.ai/api/v1/openapi.json Auth: Authorization: Bearer . Keys are issued per principal and shown once. ## Rules - Every caller is a principal. A key belongs to one principal, a person or an agent, in one company. Whatever the key does is recorded as that principal, on the same history as everyone else. - No row without evidence. A promise is filed with the exact words, the message they came from, and a locator pointing back to it. Without the words there is no row. - The quote must be in the message. The quote has to appear in message_text exactly. Whitespace may differ; case, punctuation and wording may not. A quote that fails is rejected with guard_failed and nothing is written. Copy the words, never paraphrase them. - Agents propose, people dispose. What an agent records is a candidate until a person keeps it. An agent can keep only under an auto_keep policy a person granted it, and never a promise it made itself. The database enforces that, not the API. - Ask before you claim. Call check_claim before you state a capability. Only verified may be said as fact; otherwise use say_instead. Today it answers unverified, because the register of checked claims is not built yet. It fails open: a fault on our side answers unverified, never an error that stalls your reply. - Scopes. A tool needs its authority on both the principal and the key. Read tools need only a valid key. Missing the authority answers 403; a bad, revoked or expired key, or a paused principal, answers 401. - Limits. 120 calls a minute per key, per server instance. Over that answers 429 with Retry-After. ## Tools - whoami (needs any key): The principal this key acts as, its company, what it is allowed to do, and whether it may keep anything without a person. Call it first to learn which tools you can use: a tool needing an authority you lack is refused. - list_assertions (needs any key): List promises (and later claims and entitlements) in this company's ledger. By default it returns what a person has kept (status open, satisfied, broken or withdrawn), hides exploratory promises, and sorts by due date. Pass status ["candidate"] to see the review queue. past_due is computed from due_at against today at the moment of the call; the ledger never stores lateness. Each row carries its ref, which get_assertion takes for the full record with quotes. - get_assertion (needs any key): Everything about one assertion, by ref: every quote that mentions it with where it was said, the linked pull requests and issues, the deals waiting on it, its full history of decisions, and the latest verification with the date it ran. Quotes are the customer's or the speaker's exact words. Use this before telling a customer anything about a promise. - promised_not_started (needs any key): Open firm and soft promises with no pull request or issue linked, ranked by the open pipeline each one blocks, then by due date. exposed_cents counts only deals the promise blocks; pipeline_cents is every open deal attached, for context. days_past_due is computed at the moment of the call. - shipped_not_told (needs any key): Promises whose linked work has all merged or closed, where nobody has told the customer since it shipped. Oldest first. A promise with any satisfying work still open is not here, because half shipped is not shipped. - gaps (needs any key): Both lists from /gaps in one call, recomputed now. not_started: open firm and soft promises with no pull request or issue linked, ranked by the pipeline each blocks, then due date. not_told: promises whose satisfying work has all merged or closed, with nobody telling the customer since; each row carries any "looks told" proposals the told sweep was not sure enough to act on. totals count distinct open deals that a blocking promise on the list blocks, each deal once, and either_cents counts a deal behind both lists once, so it is not the sum of the two. Row money is for reading only. - ledger_totals (needs any key): The money at the top of the ledger. exposed_cents sums distinct open deals blocked by at least one open blocking promise, each deal counted once however many promises it waits on. past_due_cents is the part behind a promise already late today. attached_cents is every open deal attached to any open promise, for context, not exposure. An inferred deal nobody confirmed counts nowhere. - ledger_overview (needs any key): The counts and money at the top of the ledger in one call: kept promises, how many are open, past due today, blocking a deal, owned by you, and owned by nobody; candidates waiting for review; claims and entitlements on the spine; and the totals from ledger_totals (each deal counted once, only blocking promises carry money). Exploratory promises are left out of the counts, as the ledger hides them by default. Everything is computed at the moment of the call. - first_run_summary (needs any key): What the ledger holds so far, for a first look: promises kept, how many are past due today, how many shipped without the customer being told, the open pipeline waiting on a blocking promise (each deal counted once), candidates waiting for review, the three oldest promises still owed, and where the promises came from by source. Every count is computed at the moment of the call. - list_candidates (needs any key): The candidates waiting for a person to keep or discard, ranked by confidence times strength times account value, highest first. Each row carries the exact quote, who said it to which account, where it was said (source and locator), and the resolved due date with its precision and the phrase it came from. Exploratory remarks are hidden unless asked for. counts gives the size of every filter over the whole queue. - list_accounts (needs any key): The customers in this company's ledger, by name, with each one's id, domains, open pipeline (counted deals only: an inferred deal nobody confirmed is left out), renewal date, open promise count and the CRMs it is linked to. Use an id or an exact name wherever another tool takes an account. - get_account (needs any key): One account in full: its domains, the CRM records it is linked to, its open promises (lateness computed at the moment of the call), its deals with whether each counts, and the revenue exposed. exposed_cents sums distinct open, counted deals that at least one open promise blocks, where both the promise and its link to the deal are marked blocking; each deal counts once. open_pipeline_cents is every open, counted deal, for a prospect. renewal_arr_cents and renewal_at are the CRM's figures for an existing customer, null when the CRM has none. currencies lists every currency the sums mix. - list_deals (needs any key): Deals in this company's ledger: synced from the CRM, inferred from mail, or typed by hand. Each says whether it counts toward totals; an inferred deal nobody confirmed does not. Filter by account, source, status, or unconfirmed only, which is the list of deals waiting for a person's one-click confirm. - export_ledger (needs any key): Every kept promise in this company's ledger (open, satisfied, broken, withdrawn, exploratory included), each with its evidence: the exact quote, who said it, when, the source and the locator that points back to the message, the second of the call or the page. For a backup, an audit, or leaving. days_past_due is computed at the moment of the call. Candidates and discards are not included. At most 5000 promises. - product_health (needs any key): The two numbers that say whether CommitOps is working for this company: keeps per active week, and the ratio of keeps to discards in the review queue. An active week is a Monday-to-Sunday week (UTC) in which anyone kept or discarded a candidate. A falling keep to discard ratio means the extractor is proposing things people throw away. Returns counts only, per week, over the last `weeks` weeks (default 12), plus the kept rate over the same window. - spend_this_month (needs any key): What this company's model calls cost this calendar month (UTC), against the monthly budget. Returns spend, budget, remaining, the warning flag at 80 percent and the stop flag at 100 percent, and a breakdown per sweep and model with calls and tokens. At or past the budget no model is called until the month turns or the budget is raised with set_budget. This is what OpenRouter charged us, never the cost of the work a promise needs. - get_analytics_setting (needs any key): Whether this company has turned product analytics off. The events never carry customer words (enums, numbers and our own ids only); turning them off stops even those counts leaving the system. - current_plan (needs any key): This company's plan: the tier (which objects it can carry), the band (accounts under management, from the highest count of accounts with an open assertion in the last 90 days), the subscription status, the renewal date, any downgrade waiting for renewal, every cap against what is used now, and every feature_key the plan grants. Seats and agents are never counted or capped. Reading is never blocked by the plan. - plan_grid (needs any key): The public price list as data, read from the same table that gates every plan: each tier and band with its monthly and annual price in cents (annual is two months free; null means quoted), the objects it carries, its caps and what it includes; the account bands; and the add-ons. Flat per company. Never per seat and never per agent. - check_claim (needs any key): Ask before you state a capability to a customer, e.g. "we have EU data residency". The answer is verified, false or unverified, with the matching claim, the date it was last checked, one line of evidence, and a sentence to say instead when it is not verified. Only verified may be said as fact. It fails open: anything wrong on our side answers unverified with a reason_code, never an error. Verified needs a true check inside the claim's recheck window; false comes with the date of the check that said so. The statement is never stored; a salted hash is kept to count calls. - list_claims (needs any key): Every kept claim (what the company says the product does today), ranked by blast radius: claims needing someone first, then those on a public page still showing, then by how many places they appear, then the stalest check. Each carries its state worked out now from the latest dated check (false, verified, expired, never_checked), where it appears, what checks it and who checked it last. Filter with needs_attention, verified, false_published (false and still on a public page), attestation_expired or never_checked. Reading is never refused by plan. - get_claim (needs any key): One claim in full, by ref (K-021): its state now, every place it appears and whether it still does, the checks configured, every dated verification newest first, the overclaims that matched it, and when it stopped being true: the date the latest run of false results began, how long it had been true before, where it was still showing then, and who repeated it to a customer afterwards, with whether that agent called check_claim. Reading is never refused by plan. - list_claim_candidates (needs any key): Claims proposed from pages, uploaded documents or overclaims, waiting for a person to keep (keep_candidate) or discard (discard_candidate). Each with the words it came from and where. - list_claim_surfaces (needs any key): The pages this workspace asked us to read for claims, with when each was last read and what happened, and the uploaded documents. - list_overclaims (needs any key): Capability statements one of our people or agents made to a customer that the register cannot back: matched a claim whose latest dated check is false, matched one nobody checked or whose check lapsed, or matched nothing. False ones first. Each names the speaker, the account, the claim and the date of the check the register answered from, and for an agent whether it called check_claim around then. - list_entitlement_drift (needs any key): The latest reconciliation: per account, what the contract says against what the system grants, with where it was read and a direction, led by under_granted (a customer paying for something they cannot use, the churn risk nobody reports). By default only terms that disagree; direction filters to one, or all includes matches. The KPI line comes with it: over-granted per year at the terms' prices, accounts that cannot use what they bought, the ARR behind them (each account once, from the CRM), breaches. Also lists the sources. Reading is never refused by plan. - get_entitlement (needs any key): One entitlement in full, by ref (E-031): the clause verbatim with its page and document, each parsed term, and the places it disagrees: the contract, the linked claim in the register (a pricing page line, with whether its last check passed) and every source's latest value with its locator, the code line included (src/lib/limits.ts:34). The comparison now, every dated run's direction for it, and its verification history. Reading is never refused by plan. - list_contract_terms (needs any key): The entitlement terms read from signed contracts: candidates waiting for a person, and kept terms, each with the clause verbatim, its page and document, the parsed feature_key, operator, value and unit, and any linked claim. Also lists the contracts uploaded. Filter by status (candidate, kept, all) and account. Reading is never refused by plan. - export_entitlement_drift (needs any key): The latest reconciliation as rows for finance: account, feature, what the contract says and what the system grants, where it was read, the direction, over-granted per year at the term's price with its basis (contract or price_list), the account's ARR, the contract reference and the clause. Disagreeing terms only unless all is true. Totals count each account once. These are revenue figures at a price and ARR; no cost is in them. Reading is never refused by plan. - agent_scoreboard (needs any key): Every principal in this company, people and agents on one list, with what each may do, what each promised in the window, how many of those were kept (the work merged), how many are broken (open and past due, computed now, never stored), and how many claims it made turned out false. Sorted by broken promises, then false claims. Also the check_claim counts for the last 7 days and which agents call it. On plans below Company the numbers are null and included is false; the list of principals is still returned. - list_auto_kept (needs any key): What agents kept under an auto_keep policy: each live policy with who granted it and when, counts of rows kept this way, sampled and reviewed, and the rows themselves, newest first. One machine-kept row in five, starting with each agent's first, is sampled for a person to review. Pass queue_only to see only sampled rows nobody has reviewed yet. - list_work_items (needs any key): List the pull requests, merge requests and issues this company's GitHub App, GitLab, Linear workspace and Jira sites have sent, newest first, with the promises each is linked to and any link waiting for a person to confirm. CommitOps mirrors the key, title, URL and state; the work itself stays in those tools. A GitLab merge request is kind pull_request. Filter by provider, state, or whether anything is linked. - get_promise_page (needs any key): What one account's promise page shows (pass account), or the public company page (pass company: true), built by the same code the page uses, so it is exactly what a viewer reads: titles, plain statuses, and only the dates, work and owners the options allow. Never a quote or an amount. preview is the page as it reads now even when nobody can open it; live says whether a viewer can. Also the link's prefix and age (never its token), and views in the last 30 days. - get_digest (needs any key): Where and when the daily Slack digest goes, and when it last went. Null when no channel is chosen. - list_recordings (needs any key): List the recordings a connected transcript source (Fireflies, Granola, Zoom, Gong) has listed, newest first: ids, start times, lengths, how many turns and speakers, how many turns were queued for extraction, and how many quotes were kept as evidence. Never a title or a word of the call. A recording with only our own people on it is internal and was never read. - get_evidence_playback (needs any key): For one piece of call evidence (its evidence_id, from get_assertion), the time into the call where the quoted words begin, as milliseconds and as mm:ss, and the provider's page for the recording. When the provider gave no timing (precision note), there is no time: show none rather than 0:00. No provider documents a link that opens at a moment yet, so url_at_offset is false and the time is shown beside the link. - list_asks (needs any key): Inbound requests from customers, clustered across wordings ("sfdc sync", "push to salesforce" and "bidirectional CRM" are one ask), with mentions in the window (180 days by default). Each ask carries two dollar figures over distinct open deals: mentioned_cents (deals on accounts that asked) and alone_cents (deals where this ask is the only open blocker). Ranked on alone_cents, then mentioned_cents, then accounts; never by cost and never by volume first. roadmap.state is worked out from linked work at the moment of the call. - get_ask (needs any key): One ask: its figures as on list_asks, every mention with the customer's exact words and the pointer back to where they said it, the deals behind it (with whether this ask blocks each and whether it is the only blocker), and any promise already made about it. - get_review (needs any key): The stored Monday page for one ISO week: what was promised, shipped, told, slipped and overdue, cost to build with measured and modeled kept apart, who carries what, and what changed, each figure with the refs behind it. Built by the Sunday sweep (or build_review_now) and kept as it stood then. snapshot is null for a week nobody built. Counts, sums, refs, titles and account names only; never a quote. Also returns the review settings and the neighbouring weeks. - list_delivery_runs (needs any key): Every delivery run, newest signature first: a closed-won deal and the promises made to that account while selling it, with counts done, in progress, not started and late (computed now). A run opens by itself when a deal turns closed won. - get_delivery_run (needs any key): An account's latest delivery run with its rows: each promise made while selling, with owner, due date and lateness (computed now), state (done, in progress, not started, from the linked work), and whether the customer was told. other_runs lists earlier runs for the same account. - list_documents (needs any key): List the Google Drive files chosen and the Notion pages shared with CommitOps: what kind each is, the account it belongs to, when it last changed and when it was read, and the outcome of the last read. A document with no account that is not a questionnaire or RFP is not read until someone names one with set_document. - list_sibling_feeds (needs any key): List the RepoOps and SalesAsCode feeds this company connected: the agent each pushes as, its source, when it last pushed and how many pushes it made. An empty list is normal: CommitOps works without either sibling. - list_teams (needs any key): This workspace's teams, each with its members (people and agents) and the authority each holds on that team's rows, and whether teams are on. With teams on, someone who is not an owner sees only their teams' accounts and assertions, plus those no team holds. - get_sso (needs admin): This workspace's SSO connection (SAML 2.0 or OIDC): the bound domains, the identity provider's entity id and sign-on URL or OIDC issuer and client id (never the secret), when each signing certificate expires, whether SSO is required, when it last tested good and when someone last signed in, and the URLs to paste into the identity provider. Scale only to configure; reading is never blocked. Needs admin. - get_audit_export (needs admin): One audit export by id, or the 20 most recent when no id is given: its status, who asked, when it was made and when the file expires, its counts, the SHA-256 of the file and of its manifest, and the signature. Pass include_bundle true with an id to receive the .tar.gz itself as base64 (up to 8 MB; larger ones download from /settings). Needs admin. - record_promise (needs propose): Call this the moment you commit to something for a customer, so the company knows what you promised. Send the exact words of the commitment as quote and the full message you sent as message_text; the quote must appear in the message verbatim, whitespace aside, or the call is rejected and nothing is written. The promise is filed as a candidate made by you, with the message as evidence. It is never kept on your say-so: a person reviews it, and you can never keep your own promise. Retrying the same quote from the same message returns the first row. - propose_assertion (needs propose): Propose a promise somebody made to a customer, found in a message, a transcript or a document you have. Send the exact words as quote, the full text they came from as message_text, who said it as speaker, and a locator pointing back (a message id, a recording offset, a page). The quote must appear in message_text verbatim, whitespace aside, or the call is rejected and nothing is written. The promise is filed as a candidate for a person to keep or discard. Today only promises can be proposed; claims and entitlements follow. - keep_candidate (needs keep): Move a candidate from the review queue into the ledger, as open. This is the decision that makes a promise count. A person with the keep authority may keep any candidate. An agent may keep only under an auto_keep policy a person granted it, within that policy's bounds, and never an assertion it made itself; the database refuses those and this tool returns the refusal. Optionally set the owner who must deliver it. - discard_candidate (needs keep): Remove a candidate from the review queue because it is not a real commitment, is a duplicate, or names the wrong account. The discard is recorded with you as the actor and counts in the kept rate. Needs the keep authority. Optionally say why with a reason code; it labels the example the classifier learns from. - link_work (needs link_work): Link a promise, by ref, to a pull request or issue the work sources mirrored, as a link a person made. It writes the link, a dated history event, and a work_link verification, which reads true once every satisfying item has merged or closed. A linked pull request gets the CommitOps comment unless the org turned comments off. Both the ref and the work item must be in your org; anything else is not found. Overrides an earlier unlink of the same pair. - unlink_work (needs link_work): Remove the link between a promise and a work item, with a dated history event and a new work_link verification. No automatic pass will link the pair again; only link_work can. Use it when a link is wrong: a wrong link tells a founder something shipped when it did not. The pull request's comment is updated to match. - confirm_proposed_link (needs link_work): Confirm a link the similarity pass proposed between a promise and a work item. Similarity never links on its own; this call is the person deciding. It becomes a link a person made, with its score kept as the confidence, a work_link verification, and the PR comment. - reject_proposed_link (needs link_work): Reject a link the similarity pass proposed. The refusal is kept, so no pass proposes or links that pair again. Rejecting a wrong match is as useful as confirming a right one. - match_now (needs link_work): Run the four match passes for one promise against the work already mirrored, instead of waiting for the sweep. Pass 1, Satisfies C-142 in a PR or issue, links at 1.00. Pass 2, the same roadmap slug, links at 0.90. Pass 3, title similarity above 0.82, only proposes: the proposals come back with their scores for a person to confirm or reject. Pass 4 is no match, which is a correct answer. - set_roadmap_slug (needs link_work): Set or clear the roadmap slug on a promise, such as saml-sso. Pass 2 links the promise at 0.90 to any pull request or issue carrying the same slug: a GitHub or Linear label named roadmap:saml-sso, or a Linear project whose name reduces to it. Runs passes 1 and 2 for the promise at once. Send null to clear it. - edit_candidate (needs keep): Correct a candidate before it enters the ledger: its title, owner, due date, strength or whether it blocks a deal. Each change is written to its history with you as the actor (a title change records that the title changed, not the words). Set keep to true to keep it in the same call, under the same rules as keep_candidate. The quote and its source never change; they are the evidence. Needs the keep authority. - paste_source (needs propose): Add a call transcript or an email thread as text, for one account, and read it for promises. Lines that start with a speaker label ("Dana Whitfield: ...", optionally after a [00:12:30] timestamp) become turns; a speaker who is one of this company's people, or is listed in our_speakers, is our side. The paste becomes its own source, so deleting it later deletes every word it contributed. With extract_now (the default) it is read at once and the new candidates come back by ref; otherwise the extract sweep reads it. Every result is a candidate for a person to keep or discard. Pasting the same text for the same account and time again changes nothing. - move_due_date (needs keep): Change the date an open promise is due, for example after the team re-plans. The old and new dates are written to the promise's history with you as the actor and an optional note, and the history is never rewritten, so anyone opening the promise sees that the date moved and when. Moving a date does not tell the customer anything. Needs the keep authority. - assign_owner (needs keep): Set who must deliver an open promise or a candidate: a person or an agent in this company, by principal id or display name. Pass null to leave it with nobody, which puts it on the no-owner filter. The change is written to the history with you as the actor. Needs the keep authority. - withdraw_assertion (needs withdraw): Take an open promise off the ledger because the company will not do it, the customer no longer wants it, or it was superseded. It stays visible as withdrawn with its quotes and history, and leaves every open list and total. The withdrawal is written to the history with you as the actor. Withdrawing does not tell the customer. Needs the withdraw authority. - draft_told_email (needs communicate): Write the note telling a customer that a promise shipped, as a draft in the caller's own Gmail (an agent's goes in the Gmail of the person who operates it). It is never sent: the person reads it and sends it, or not. The draft is offered only when every satisfying pull request or issue has merged or closed and the latest work_link verification says so and is dated after the last merge; otherwise the reason names what is not shipped. It is addressed to the customer contact on the evidence, or to `to`, which must be an address at the account's domain. It claims only that the work shipped and when. Pass dry_run to see the check and the words without writing anything. Needs the communicate authority and the Write drafts in Gmail permission on /connect. - mark_told (needs communicate): Record that the customer was told a promise shipped, when it happened somewhere CommitOps cannot see. It writes a communication with you as the actor and a dated history row, and the promise leaves shipped and not told when the date is on or after the work shipped. reference is a pointer (a message id, a link, "Oct 14 call"), never what was said. Needs the communicate authority. - confirm_told (needs communicate): Decide a "looks told" proposal from the told sweep, by its id from the gaps tool. confirm true records the communication it found and the promise leaves shipped and not told; confirm false rejects it, and that message or meeting is never proposed again for this promise. Needs the communicate authority. - run_told_sweep (needs communicate): Look now, instead of at the next hourly run, for customers already told about promises on shipped and not told: mail sent to the account's domain after the merge, a draft we made that has since been sent, and meetings with the account after the merge. A strong match records the communication and drops the row; a weak one becomes a "looks told" proposal for a person. Reads up to 25 rows per call. Needs the communicate authority. - set_public_visibility (needs communicate): Choose where a kept promise is shown outside the company. account_page puts it on its own account's promise page, which only that customer's link opens. company_page puts it on the company's public page at /p/org/, which anyone can open, and needs a public title first (set_public_title), because that page names no customer. Nothing is shown until a person turns it on. A viewer sees the title, a plain status, and only what set_promise_page_options allows; never a quote or an amount. The change goes in the promise's history. Needs the communicate authority. - set_public_title (needs communicate): The title a customer reads on the promise page, in the company's words. Without one, the account page shows the ledger title and the company page does not show the promise at all. Write it for the customer: what they will get, not who asked or what a deal is worth. Pass null to clear it, which also takes the promise off the company page. The history records that the public title changed, not what it says. Needs the communicate authority. - create_promise_page_link (needs communicate): Create the link that shows one customer account its promise page: the promises marked for its page, each with a plain status. No sign-in for the viewer, so treat the link like a password. The token is returned once and never again; to send it to someone new later, copy it from where you sent it, or rotate. One live link per account: if one exists this refuses, and rotate_promise_page_link replaces it. Needs the communicate authority. - rotate_promise_page_link (needs communicate): Replace an account's link with a new one. The old link stops working at once, for everyone who has it, and any site embedding it shows that the page is not available. The new token is returned once. Use it when a link went somewhere it should not, or to send a fresh one. Needs the communicate authority. - revoke_promise_page_link (needs communicate): Turn an account's link off. Anyone who opens it after this sees that the page is not available, with no hint of why. Nothing about the promises changes. Needs the communicate authority. - set_promise_page_options (needs admin): Turn account pages on or off for the whole company, and choose what a viewer sees beside each title: the promised date, the work items behind it (keys, titles and links, which can name repositories), and owner names. All four start off. Dollar figures, quotes and deals are never shown, and there is no option to show them. Needs admin. - set_company_page (needs admin): The company's public promise page at /p/org/: the promises marked public with set_public_visibility, under their public titles, with no customer named. Set enabled, the slug, and the hosts allowed to embed it with /embed.js, beyond the company's own domains ("example.com" allows it and its subdomains over https; "localhost:3000" allows a local test page). embed_domains replaces the whole list. Returns the one script tag a site adds. Needs admin. - propose_deal (needs propose): For an account with no CRM deal: propose an inferred deal seeded from a promise's evidence, the mail thread it was read from. The amount is the one dollar figure in our own words around that quote, or empty when there is none or more than one; the caller never supplies it, so no figure is invented. It enters no total until a person confirms it with confirm_deal. Refused when the account already has an open CRM or inferred deal: attach the promise to that one instead. - confirm_deal (needs keep): A person confirms an inferred deal is real, optionally setting or correcting its amount at the same moment. From then on its amount may enter totals, through any promise marked blocking on it. Only a person can confirm; an agent's call is refused. A CRM deal needs no confirming. - edit_deal (needs keep): Change an inferred or manual deal's name, amount, currency, stage, close date or status. A CRM deal is refused: edit it in the CRM, which stays the system of record. When an agent changes a confirmed deal's amount or currency, the confirmation is cleared and a person confirms again. - attach_deal (needs propose): Link a promise to a deal on the same account, so the deal shows on the promise and the promise on the deal. Pass is_blocking true only when a person has said the deal waits on this promise: only a person may set it, and an agent's call with it is refused. A deal's amount enters a total only when the promise is blocking (mark_blocking) and this link is blocking, and each deal counts once however many promises it waits on. - mark_blocking (needs keep): A person says a promise does, or does not, block a deal. Sets the promise's blocking flag, and, when deal_id is given, the flag on its link to that deal too, attaching it if needed. A total counts a deal only when both are set. Only a person can call this. - sync_crm_now (needs admin): Bring the next sync of each connected CRM (HubSpot, Attio, Salesforce, Pipedrive) forward to now, or of one provider. A sync reads companies with their domains and open and recently closed deals with amount, currency, stage, dates and owner, only what changed since the last pass, and never notes, emails or activities. It runs on the job runner within minutes; running is true when one is already under way. Needs admin. - merge_asks (needs keep): Fold one or more asks into another when they are the same request in different words. Every mention moves to `into`, and the others are gone. Pass title to rename the one that stays. Needs the keep authority. - split_ask (needs keep): Move some of an ask's mentions into a new ask, when two different requests were clustered together. Pass the evidence ids from get_ask; at least one must stay behind. The new ask is named from the first moved mention unless you pass title. Needs the keep authority. - mark_not_ask (needs keep): Take an ask off /asks because it is not a request for the product: a bug report, a question about billing, chatter the detector misread. Its words stay attached, so the next sweep never raises them again. Needs the keep authority. - send_ask_to_linear (needs link_work): Turn an ask into a Linear issue through the org's Linear connection, only when that connection was granted write. Otherwise nothing leaves and you get a plain summary to copy: the ask's name, accounts, the two dollar figures, the roadmap state and a link back, never a quote or an account name. team_key picks the Linear team ("ENG"); the workspace's first team otherwise. An ask already sent returns its issue. Needs the link_work authority. - build_review_now (needs keep): Assemble a week's Monday page now instead of waiting for Sunday, and store it, replacing that week's page if there was one. A week still running is read up to this moment. Sends nothing. Needs the keep authority. - send_review (needs communicate): Send a stored week's page now: as a Gmail draft addressed to the review recipients, in your own Gmail (an agent's goes in its operator's), which you then send; and as a post in the digest's Slack channel. Choose either or both; by default, the ways the settings name. Counts, refs, titles and account names, never a quote. Build the week first if it has no page. Needs the communicate authority. - open_delivery_run (needs keep): Open a run for an account by hand: when a person marks a deal won, or the CRM has not caught up. With opportunity_id, a manual or confirmed inferred deal still open is marked won today, which opens the run; a CRM deal is left as the CRM has it and the run opens beside it. Without one, the run opens for the account as of today. owner sets who carries the handoff. An existing run is returned, with the owner updated when given. Needs the keep authority. - send_delivery_status (needs communicate): Write a plain note to the customer saying where each promise made during the sale stands (done and when, in progress, not started yet, and the date we gave), as a draft in your own Gmail (an agent's goes in its operator's). It is never sent by us. It uses the promise page title when one is set, never a quote, a ref or an amount. Addressed to the customer contact on the evidence, or to `to`, which must be at the account's domain. Pass dry_run to see the words and write nothing. Needs the communicate authority and Write drafts in Gmail on /connect. - add_claim_surface (needs propose): Add a page of this company's own site (the homepage, the pricing page, a features or security page) to read for capability claims. It is read within the hour and then once a day, politely: robots.txt is respected and the user agent names us. What it claims arrives as candidates for a person to keep. API reference docs are refused (any path like /api, /reference or /openapi, or an api. host): the register stays out of OpenAPI drift. Company plan and above. - crawl_surface_now (needs propose): Read one page added with add_claim_surface right now instead of waiting for the hourly sweep, and say what it found: new candidates, lines matching existing claims, and lines that disappeared since the last read. A page we could not read (robots, an error, a timeout) changes nothing about what it said before. Company plan and above. - upload_claim_document (needs propose): Read a sales deck, a signed security questionnaire or an RFP answer for capability claims. Send the file as content_base64 (PDF or DOCX, read by its bytes) or a pasted answer as text. Each claim found becomes a candidate, or one more place an existing claim appears, pointing at its page. The same file twice is one document. Over the HTTP API the whole body is capped at 1 MB, so a file of about 700 KB; the screen takes up to 4 MB. A scanned PDF with no text layer yields nothing. Company plan and above. - add_capability_check (needs verify): Say how a claim is verified. endpoint_check: {url, method, expect_status, json_path?, op?, value?} hits an HTTP endpoint. flag_check: {adapter: json_endpoint, url, flag_key, expected} reads a flag from a JSON document. config_check: {adapter: json_endpoint, url, json_path, op, value?} reads a config value. code_check: {mode: merged_pr, pr: "owner/repo#123"} passes while that pull request is merged and not reverted, from what our GitHub App can read; reading files (mode file_pattern, adapter repo_file) needs the Contents permission, which the app does not have, so those answer unknown. human_attestation: a person confirms it with attest_claim; it expires after recheck_days and the register nags. Every run writes a dated verification. Company plan and above. - run_check_now (needs verify): Run one automated check on a claim now instead of waiting for the daily sweep, and get what it found, dated. A false result moves the claim to broken; a true one to satisfied; unknown (it could not run) moves nothing. Every run is kept as history. A human attestation is not run: use attest_claim. Company plan and above. - attest_claim (needs verify): As a named person, confirm that a claim is true today (result true) or say it is not (result false). Dated now, recorded with your name, and good for the claim's recheck window (or its attestation check's), after which the register shows it as attestation expired and check_claim answers unverified until someone attests again. Only a person may attest; an agent is refused. A false attestation moves the claim to broken. Company plan and above. - set_claim_details (needs verify): Set what check_claim offers to say instead when this claim is false or unverified (say_instead, e.g. "EU residency is on the roadmap, with no date committed"), how many days a check stays good (recheck_days), and whether it is public. Company plan and above. - resolve_overclaim (needs verify): Close an overclaim once someone has acted: corrected (the customer was told the right thing), claim_is_true (a person confirms it; attest the claim too so the register says so), not_a_claim (the detector misread it), or added_to_register (it matched nothing, and it should be a claim: this proposes one from the same words, for a person to keep). Company plan and above. - upload_contract (needs propose): Read a signed order form, MSA, amendment or renewal for one customer account and propose its entitlement terms: each a feature_key (api.rate_limit, seats, sso, data_residency), an operator (eq, gte, lte, includes, unlimited), a value and unit, and the clause as a verbatim quote with its page. Send content_base64 (PDF or DOCX, read by its bytes) or text. The model reads it under zero data retention routing; every clause must appear word for word on a page or the term is thrown away and counted. Terms arrive as candidates for a person to keep with keep_contract_term. The same file twice is one document. A scanned PDF with no text layer yields nothing. A CLM connector is not built. Contract ingestion is included on Scale and a $299 add-on on Team and Company. - keep_contract_term (needs keep): Keep a proposed contract term (E-031) as an entitlement, so reconcile_entitlements checks it against the running system. Correct the parse first if it is wrong: feature_key, operator, value, unit, term_kind (grant, or obligation for residency, retention and the like, where a difference is a breach), more_is_better (false for a response time), and price_cents_year (one unit for a year, from your price list when the contract states none; it prices over-grants). claim_ref links a claim in the register that says the same thing, such as a pricing page line. Needs the keep authority; the database refuses an agent keeping a term it proposed. Contract ingestion is included on Scale and an add-on below. - add_entitlement_source (needs verify): Say where the running system records what each account is granted. kind plan_config: {adapter: json_endpoint, url} or {adapter: inline, document} (a config file's JSON, no database needed) or {adapter: repo_file, repo, path}, with {plans: {: {: value}}, accounts: {: {plan, overrides}}} in the document (plans_path, accounts_path and features move or rename the parts). kind flag_service: {adapter: json_flags, url or document, flags: {: }}. kind code, the hardcoded check: {files: [paths], account_plans: {: }, mappings: [{feature_key, symbol, field?, unit?}], repo?} reads constants such as RATE_LIMITS.enterprise = 10_000, objects keyed by plan, ENTERPRISE_SEATS = 50, if (plan === 'enterprise' && count > 10000), and lists like SSO_PLANS, in TypeScript, JavaScript and Python, with the file and line. Code is read from files you hand read_entitlements_now, or through the GitHub App once it has Contents read. The same name again replaces the config. Scale plan. - read_entitlements_now (needs verify): Read one source (by id or name) or every enabled one now, and write what each account is granted as dated rows with the source and a locator: the file and line for code, the JSON path for a config, the flag and rule for a flag. Nothing earlier is overwritten. For a code source, hand over the named files in files when the GitHub App cannot read the repo (it has no Contents permission today). For a plan_config or flag source, document replaces the configured URL for this read. Then call reconcile_entitlements. Scale plan. - reconcile_entitlements (needs verify): Compare every kept entitlement with the latest value each source read for that account, and record the run: a dated row per term with its direction (under_granted, over_granted, not_granted, mismatch, breach for an obligation the system plainly violates, or match), and a dated verification per entitlement, which moves it to broken when it differs and to satisfied when every term matches. Nothing earlier is overwritten. read_first reads every enabled source before. Returns the KPI line: over-granted per year at the terms' prices, accounts that cannot use what they bought and the ARR behind them (each account once), and breaches. Scale plan. - create_credential (needs admin): Issue an API and MCP key for yourself or an agent you operate (an owner may issue for anyone). The key is returned once, in this response, and cannot be shown again; store it before you do anything else. It carries only scopes your own key carries and the target principal holds, and expires after expires_in_days (90 unless you say). Needs admin. - list_credentials (needs admin): The keys you may manage: your own and those of agents you operate, or every key in the company for an owner. Shows the prefix, scopes, last use, expiry and revocation. Never shows a secret. Needs admin. - revoke_credential (needs admin): Revoke a key by its id or its 8 character prefix. It stops working on the next call. Revoking is permanent; issue a new key instead of reviving one. Revoking an OAuth access token also revokes the refresh tokens behind it, so the client has to ask a person again. Same reach as list_credentials. Needs admin. - set_budget (needs admin): Set this company's monthly ceiling on model spend, in US dollars. At or past it, extraction stops calling a model until the month turns. Zero stops every model call. warn_ratio is the share of the budget that raises the warning, 0.8 unless given. Needs the admin authority. Returns the month's status under the new budget. - set_analytics_opt_out (needs admin): Turn product analytics off (opted_out true) or back on for this whole company. Off means no event is sent for anyone in it from the next call on. Needs the admin authority. - set_digest (needs admin): Choose where and when the daily Slack digest goes: a public channel by name ("#founders") or id, a local time (default 08:30), the weekdays (default Monday to Friday), the company's IANA time zone ("America/Chicago"), and whether it is on. Fields left out stay as they are. Slack must be connected on /connect first. The digest carries refs, titles, account names, dates and counts, never a quote. Needs the admin authority. - send_digest_now (needs communicate): Post today's digest to the chosen Slack channel now: new candidates since the last digest, promises due this week or late, and what shipped with nobody telling the customer. The scheduled one still goes at its time. Refs, titles, account names, dates and counts only, never a quote. Needs the communicate authority. - set_cost_model (needs admin): The two numbers the modeled cost on the Monday page needs: loaded_daily_rate_cents, what one engineer-day costs the company loaded (null clears it, and then no estimate is made), and parallelism, how many things an engineer carries at a time (default 2). The page shows the formula and these inputs beside the estimate and never adds it to measured spend. Fields left out stay as they are. Needs the admin authority. - set_review_schedule (needs admin): Who receives the Monday page and when the Sunday sweep assembles it: recipients (principal ids of people in this workspace), review_day (ISO weekday, 7 is Sunday), review_at (HH:MM in the org's time zone, default 18:00), by_email (a draft in your own Gmail addressed to them) and by_slack (a post in the digest channel). The org's time zone is set with set_digest or here. Fields left out stay as they are. Needs the admin authority. - list_principals (needs any key): Everyone who can act in this company, people and agents in one list: name, type, role, what each may do, who operates each agent, and whether it may keep anything without a person. Use it to find a principal id before creating a key or assigning an owner. - create_agent_principal (needs admin): Add an agent to the company as a principal of its own, so what it says and does is recorded against it and scored like a person. Name it, say what kind of agent it is and whose it is (agent_vendor), and name the person accountable for it (operated_by, yourself unless you are an owner). It starts with the authority you give it, never more than you hold, and may only propose until an owner sets a bounded auto_keep policy. Then issue it a key with create_credential. Needs admin. - update_principal (needs admin): Set a principal's authority, pause or retire it, or make a person an owner. An owner may change anyone but themselves; anyone else with admin may change only the agents they operate. A person who joined by company domain starts with no authority, and this is how an owner grants it. Authority granted never exceeds your own. Pausing an agent stops every key it holds on the next call. Needs admin. - invite_member (needs admin): Invite someone by email. When they next sign in with Google at that address they join this company with the role and authority given here, never more than you hold. Nothing is emailed; tell them to sign in at /signin. Inviting the same address again replaces the open invitation. Lasts 14 days. Needs admin. - list_invitations (needs admin): Open invitations to this company, newest first, and optionally the accepted, revoked and expired ones. Needs admin. - revoke_invitation (needs admin): Withdraw an open invitation by its id. The address can no longer join through it. Needs admin. - grant_auto_keep (needs admin): Let one agent keep candidates without a person, inside four bounds: a confidence floor, the kinds and strengths it may keep, and a daily limit. Replaces any policy it held. Only an owner may grant one, it is recorded with who granted it and when, and every row the agent keeps this way carries the policy, shows as machine-kept, and one in five goes to a person for review. The agent still may never keep anything it made itself. Adds the keep authority to the agent; its key needs keep too. Company plan and above. - revoke_auto_keep (needs admin): Take an agent's auto-keep policy away, so it may only propose again. Rows it already kept stay kept and keep the policy that allowed them; review or withdraw them separately. Removes the keep authority, which an agent cannot use without a policy. An owner, or the person who operates the agent, may revoke. Never refused for the plan. - review_auto_kept (needs keep): A person's verdict on one row an agent kept under its policy: right (a person would have kept it) or wrong (it should not be on the ledger as kept). Stored once per row and never changed. A wrong verdict does not move the row; withdraw or edit it on its page, and consider narrowing or revoking the policy. Needs the keep authority, and only a person may review; an agent is refused. - record_spend (needs any key): Report what an agent cost on one day, measured from its vendor's bill or meter, in cents. It shows as Spend on the scoreboard. Measured only: a modeled or estimated figure does not belong here and is never summed with measured cost. An agent reports for itself; a person reports for an agent they operate, or an owner for any agent. Reporting the same day again replaces the figure. - link_github_installation (needs admin): Tell CommitOps which org a GitHub App installation belongs to, so its webhooks land here. The install flow at /connect binds an installation the signed-in person can reach; this tool binds one by id, for an agent or a script: pass the installation id from the app's installation settings URL and the account it was installed on. An installation already bound to another org is refused. Needs admin. - link_linear_workspace (needs admin): Tell CommitOps which org a Linear workspace belongs to, so its webhooks land here. Pass the workspace's organization id, the organizationId on every Linear webhook. A workspace already bound to another org is refused. /connect binds a workspace through Linear's own consent; this tool binds one by id, without a token. Needs admin. - set_pr_comments (needs admin): Turn the CommitOps comment on linked pull requests on or off for the whole org. It is on by default. Off, links and verification work as before and no comment is posted or edited. A public repository's comment names only the ref, never the account or the dollars, whatever this is set to. Needs admin. - set_mr_comments (needs admin): Turn the CommitOps note on linked GitLab merge requests on or off for the whole org. It is off by default. On, a merge request that satisfies a promise gets one note, edited in place when its links change, saying which promise and, on a private project, the account, the open dollars and the date; a public or internal project's note names only the ref. The GitLab connection must hold the api scope (connect with the note grant). Needs admin. - gitlab_webhook_setup (needs admin): Give the URL and secret token to paste into a GitLab project's or group's Settings, Webhooks, for one GitLab connection, with the triggers to tick: merge request events, issue events and comments. GitLab sends nothing until a person adds it. The token is derived for this connection alone and stops working when the connection is disconnected. Needs admin. - connect_gitlab_token (needs admin): Connect a self-managed GitLab instance, which our gitlab.com OAuth app cannot reach, with an access token a person creates there: a personal, group or project access token with read_api, or api if the merge request note should be posted. The instance must be https and must not resolve to a private address. The token is checked with one call, stored encrypted, and never returned or logged. gitlab.com connects through OAuth on /connect instead. Then add the webhook from gitlab_webhook_setup. Needs admin. - start_checkout (needs admin): Create a Stripe Checkout link for Team or Company, at the band this company's accounts put it in, monthly or annual (two months free). Add-ons are optional. Tax is calculated by Stripe Tax. Returns a URL for a person to open and pay. Refuses when the company already has a live subscription (use change_plan), above 400 accounts (quoted), and for Scale (quoted and invoiced). Needs the admin authority. Answers unavailable when billing is not configured. - change_plan (needs admin): Move a live subscription to another self-serve tier at the same band and interval. An upgrade takes effect now and Stripe prorates it. A downgrade takes effect at renewal: until then the company keeps what it paid for, and current_plan shows the change waiting. Choosing the current tier again cancels a waiting downgrade. To stop paying, cancel in open_billing_portal, which also takes effect at renewal. Needs the admin authority. - open_billing_portal (needs admin): Create a Stripe Customer Portal link where a person updates the card, downloads invoices, or cancels. A cancel takes effect at renewal. Needs the admin authority and an existing billing account (start_checkout creates one). - list_sources (needs any key): List what this company has connected (Gmail or Outlook, Google or Microsoft Calendar, GitHub, GitLab, Linear, Jira, the CRMs, the transcript sources, Google Drive, Notion, Slack Connect and the RepoOps and SalesAsCode feeds), each with its state, when it last synced, any error code, its first run, and counts: for mail the external threads read and the internal threads skipped without being opened, for a calendar the external meetings stored, for documents how many are chosen and how many wait for an account, for Slack Connect the shared channels read and the internal ones skipped, and for every source the quotes stored from it. A source in needs_reconnect stopped syncing because the provider refused its grant; a person connects it again on /connect. Pasted transcripts are not listed. - disconnect_preview (needs any key): Count what disconnecting a source would delete, before anyone confirms: every quote that came from it, every assertion left with no quote from anywhere else (kept ones included), the messages waiting to be read, the threads and meetings recorded, and any work items. The record that decisions were made stays. Call this and show the numbers to the person before calling disconnect_source. - sync_source_now (needs propose): Fetch new mail, meetings, call transcripts, changed documents or Slack Connect messages for one Gmail, Outlook, Google Calendar, Microsoft Calendar, Fireflies, Granola, Zoom, Gong, Google Drive, Notion or Slack Connect source now instead of waiting for the sync sweep (every 15 minutes for mail and Slack Connect, hourly for a calendar and Drive, every 30 minutes for transcripts and Notion). Slack Connect still keeps to Slack's limit of one history call a minute outside the Marketplace. Spends up to 25 seconds fetching, then returns; the sweep carries on from where it stopped, and the extract sweep reads what was fetched. GitHub, GitLab, Linear and Jira arrive by webhook and need no sync; CRMs use sync_crm_now. A source in needs_reconnect must be connected again on /connect first. - disconnect_source (needs admin): Disconnect a source and delete everything it contributed, in one transaction: its quotes, any assertion left with no quote from another source, its waiting messages, threads, meetings and work items, and its sync jobs. For Google, the grant is also revoked at Google when no other connection uses it. Returns the counts it deleted, which match disconnect_preview taken in the same transaction. Needs admin. Cannot be undone. - connect_transcript_key (needs admin): Connect a call transcript provider that works with a key the customer pastes: fireflies (an API key from Fireflies settings, Integrations, Fireflies API, any plan) or granola (a key starting grn_, Business plan or above). The key is checked with one list call, then stored encrypted; it is never returned or logged. The first pull reads every transcript from the last 90 days, a chunk at a time, and then every 30 minutes. Connecting the same key again replaces nothing but the stored copy. Zoom and Gong connect through OAuth on /connect instead. Needs admin. - add_drive_files (needs propose): Record files a person picked in the Google Picker on /connect, so CommitOps reads them: Google Docs, PDFs and Word files, up to 10 MB each. Say what kind they are and, to find promises in them, which account they were written for. Each is read at once and again whenever it changes in Drive. CommitOps can open only files picked through its Picker; any other id is marked not_found. - set_document (needs propose): Say which account a connected document was written for, what kind it is, or who reads it. Naming an account lets CommitOps look for promises in it; marking it a questionnaire or RFP also sends its capability statements to the claim register. The document is read again on the next pass, which this call starts. Send account null to clear it. - remove_document (needs admin): Stop reading one Drive file or Notion page and delete everything it contributed: its quotes, any assertion left with no quote from elsewhere (kept ones included), and its claim surfaces. The rest of the source stays. For a Notion page, also stop sharing it with the integration in Notion, or the next pass finds it again. Needs admin. Cannot be undone. - connect_sibling (needs admin): Connect a sibling product's feed. Makes an agent principal for it (named RepoOps or SalesAsCode, operated by you), its own source so disconnecting forgets what it sent, and a key returned once in this response. Paste the key into the sibling's settings; it then pushes to CommitOps over the API or MCP as that agent. RepoOps sends measured agent spend per merged change and roadmap slugs; SalesAsCode sends deals and the promises it found, which arrive as candidates. CommitOps works without either. One feed per product. Needs admin, and an owner. - record_work_cost (needs link_work): RepoOps only. Report what coding agents measurably cost for one pull or merge request, in cents: the metered spend of the agent sessions tied to that change. attribution says how they were tied: branch (the sessions ran on the change's own branch) or file_overlap (they touched the same files, and RepoOps rated the match strong). A weaker match, or a figure from a model rather than a meter, must not be sent; spend RepoOps cannot tie to a change stays unattributed and is never spread. Stored as cost_basis measured and never added to a modeled figure. Reporting again replaces the figure. A change CommitOps has not seen is mirrored from what you send. - record_work_slugs (needs link_work): RepoOps only. Say which roadmap items one pull or merge request belongs to, as slugs such as saml-sso. A promise carrying the same slug (set_roadmap_slug) is linked to the change at 0.90 by match pass 2, as a roadmap:saml-sso label would. The list replaces what you sent before for this change, so send [] to withdraw them; slugs from the change's own labels stay. A change CommitOps has not seen is mirrored from what you send. - record_deal (needs propose): SalesAsCode only. Send one company and one of its deals, in the shape every CRM connector uses: the company's id in SalesAsCode, its name and website domains; the deal's id, name, amount in cents (null when unknown, never a guess), ISO currency, stage, open, won or lost, close date, renewal date and owner. The company links to the account CommitOps already has with exactly that domain, else becomes one; a domain shared by two accounts links to none. Stored with source crm, so it counts wherever a blocking promise waits on it. Sending the same deal again updates it. - configure_sso (needs admin): Set this workspace's SSO connection, replacing any before. SAML 2.0: pass protocol saml and the identity provider's metadata_url (public https) or metadata_xml. OIDC: pass protocol oidc, issuer (https), client_id and client_secret; the secret is stored sealed and never shown again. domains lists the workspace's own domains to bind; only addresses there sign in through it, and a domain may be bound by one workspace only. A new or changed connection is untested and not required until test_sso comes back good. People who sign in through it for the first time arrive as members with no authority. Pass remove true to delete the connection. Scale only. Needs admin. - test_sso (needs admin): Check this workspace's SSO connection: the bound domains, each SAML signing certificate's expiry and the metadata URL, or the OIDC discovery document. Returns a sign-in link, good for ten minutes; open it, sign in at the identity provider with an address at a bound domain, and when the answer comes back good the connection is marked tested and nobody is signed in. Requiring SSO waits for that. Scale only. Needs admin. - set_sso_enforcement (needs admin): Require SSO for this workspace's bound domains, or stop requiring it. While required, Google sign-in is refused for addresses at those domains, a Google session at those domains stops on its next request, and a person who signed in with Google before moves to their SSO login, keeping their authority. Requiring needs a good test_sso first. Turning it off never waits on the plan. Scale only to turn on. Needs admin. - create_team (needs admin): Create a team by name, unique in the workspace ignoring case. Add people and agents with add_team_member and put accounts or assertions in it with set_team_scope. Creating teams changes nothing anyone sees until set_team_scope turns teams on. Scale only. Needs admin. - add_team_member (needs admin): Add a person or an agent to a team (by team id or name) with the authority it may use on that team's rows (propose, keep, verify, communicate, link_work, withdraw; never admin), or change that authority, or pass remove true to take them off the team. A member's own workspace authority still applies everywhere it can see; a team grant applies only to that team's rows, and acts through a signed-in session (a key carries the principal's own authority). Scale only to add. Needs admin. - set_team_scope (needs admin): Turn teams on or off for the workspace (enabled), and put an account (account_id) or one assertion (ref) in a team, or take it out with team null. An account's team covers every assertion on it. With teams on, someone who is not an owner sees only their teams' rows plus those no team holds, on every screen and through every tool. Off by default. Turning teams off never waits on the plan. Scale only otherwise. Needs admin. - export_audit_bundle (needs admin): Build the audit export: every assertion this company has made (promises, claims and entitlements, every status), each with every quote it rests on (speaker, source, locator, said_at), every event in its history, every verification with checked_at, the work it links to, what the customer was told, and the deals waiting on it. One .tar.gz of JSON and CSV with a manifest listing a SHA-256 per file, signed with HMAC-SHA256 by a server key. Kept 7 days, then cleared. Up to 2000 assertions it is built now and comes back ready; above that it is queued and get_audit_export reports when it is ready. Scale only. Needs admin. - add_addon (needs admin): Add the white-label promise page ($99 a month; it hides our mark on the customer-facing page) or extra workspaces ($149 a month each; each covers one more workspace you own with this plan) to the live subscription, as a Stripe subscription item prorated for the rest of the period. quantity is how many extra workspaces to add; the white-label page is one. Prices come from plan_grid. Scale is invoiced, so there it is a note to us instead. Needs admin. - remove_addon (needs admin): Remove the white-label promise page, or some extra workspaces (quantity, default 1), from the live subscription, credited for the rest of the period. The promise page shows our mark again at once. Extra workspaces cannot drop below the number covered now; stop covering one with cover_workspace first. Needs admin. - cover_workspace (needs admin): Put another workspace you own on this workspace's plan, using one extra workspace this plan pays for, or take it off (covered false). A covered workspace gets this plan's tier and keeps its own people, keys and rows. It needs a signed-in person who owns both workspaces, so an agent key cannot do it. Needs admin. ## Docs - [Agent docs](https://commitops.ai/docs/agents): setup for Claude Code, Claude Desktop, Cursor and claude.ai, and the rules - [check_claim contract](https://commitops.ai/docs/agents/check-claim): POST https://commitops.ai/api/v1/check_claim, versioned, fails open - [Setting up a product's agent](https://commitops.ai/docs/agents/products): one workspace per product, a propose-only key - [Sibling feed contract](https://commitops.ai/docs/agents/sibling-feeds): how RepoOps and SalesAsCode push measured spend, roadmap slugs, deals and commitments as agents - [Security](https://commitops.ai/security): what is in the code, decided, or planned