For AI agents: a documentation index is available at https://www.plungeai.com/docs/llms.txt. Append .md to any page URL, or send Accept: text/markdown, to get markdown. Setup instructions for agents are at https://www.plungeai.com/docs/agents.md. One ozk_ key opens every plane, models included.

Documentation Index: fetch the complete documentation index at /llms.txt. Use this file to discover all available pages before exploring further.

A company is a campus. You describe it in YAML documents, save them like any workflow, and apply them. The platform compiles them into a plan and runs it: it puts items (a feature, a brief, a piece of content) through each building's offices in order, and it stops at gates where a person decides. This chapter is the REST surface for all of it. Base URL is https://api.plungeai.com; every route takes an ozk_ key (Authentication).

The same rules as Bots hold on every route here:

  • Your rows only. The key's account is the tenant. A campus another account owns answers the same 404 company_not_found as one that does not exist.
  • Four wires. JSON by default. POST/PUT bodies may be YAML, and format= or Accept picks the response format (json, yaml, markdown, text). The event feed also streams as server-sent events.
  • One error shape. {"error": {"code", "message"}} plus the X-Error-Code header (Errors, limits & headers).
Method and pathWhat it does
GET /v1/companiesyour applied campuses: mode, status, building count, approvals waiting
POST /v1/companies/{campus}/applycompile the saved documents into the stored plan
GET /v1/companies/{campus}/layoutthe compiled company: buildings, policy, floors, intake, pipeline, offices
GET /v1/companies/{campus}/snapshotthe company now: office states, active items, the line at the door, spend today
GET /v1/companies/{campus}/eventsthe event log: a JSON page after since, or a live SSE feed (Accept: text/event-stream or ?stream=1)
POST /v1/companies/{campus}/eventsa local building's node reports its events up ({events: [...]}, 1 to 200)
GET /v1/companies/{campus}/buildings/{building}/slicewhat a local building's node pulls to run it
POST /v1/companies/{campus}/itemsput an item into a building: {building, title, body?, kind?, priority?, tier?} → 201
POST /v1/companies/{campus}/items/{id}/pause · resume · retry · cancel · steeract on one item (steer takes {text})
GET /v1/companies/{campus}/approvalsthe door: pending gates and tool permissions (status=pending|approved|rejected|expired)
POST /v1/companies/{campus}/approvals/{ap}decide: {decision: approve|reject, note?}
PUT /v1/companies/{campus}/mode{mode: supervised|tiered|autonomous}, live
POST /v1/companies/{campus}/start · stoparm or disarm the campus clock; both idempotent
DELETE /v1/companies/{campus}delete a stopped or never-started company and every row of it → 204

Source: orchestration/api-gateway/routes/companies.ts (the wire) over orchestration/company-service/ (every rule; contract.ts is its surface, README.md its grammar). Every response below comes from a live walk on 2026-10-14 (UTC) against a throwaway campus that was deleted at the end. Ids are shown as ….

17.1 What a campus is

PartWhat it is
Campusa document of kind: campus: a name, a slug, a mode and its buildings in map order
Buildinga kind: building document, or a building written inline in the campus. It has floors of offices, a standard its policy follows, the intake items come through, and the pipeline an item walks
Officean ordinary CNL workflow: the agents doing the work. It is a saved workflow name, or inline {name, workflow}. An inline office is saved for you on apply as <campus>/<building>/<office>
Itemone piece of work put into a building. It walks the pipeline step by step
Gatea pipeline step where the standard's policy and the mode decide: pass it (auto) or ask a person (an approval)

location: cloud buildings run their offices on the platform once the campus clock is started. location: local buildings run on your own machine: the node pulls the building's slice and reports its events up. The cloud clock never dispatches a local building's items.

The mode decides who passes a gate. supervised asks a person at every gate. tiered asks according to the standard's tier table. autonomous asks only where a building's policy says require. There are two standards. code (the software factory) has the gates spec, build_permission, diff, merge and deploy. action (the venture studio) has the gates brief, tool_permission, content, commitment and release (orchestration/company-service/rubrics/).

17.2 The documents: kinds campus and building

Documents are compiled, never executed. Save them with POST /v1/workflows and kind: campus or kind: building (16.1). The walk below used one campus document with its building inline: a cloud building whose pipeline starts with a gate, so nothing ran and nothing was spent.

kind: campus
campus:
  name: plan-docs-…
  slug: plan-docs-…
  mode: supervised
  buildings:
    - name: Desk
      location: cloud
      policy:
        tiers: action
      floors:
        - name: "1"
          offices:
            - name: draft
              workflow:
                description: "Desk: draft one line from the item."
                tasks:
                  - type: harness
                    id: writer
                    agent: one-agent
                    goal: "Draft one line from this item. {input}"
                    mission: "You are the desk's writer."
                    allowed_tools: [task_complete]
                    max_iterations: 2
      intake:
        - api: true
      pipeline:
        - gate: brief
        - office: draft
KeyLevelMeaning
campus.name · campus.slugcampusthe slug is the {campus} of every route (^[a-z0-9][a-z0-9-]{0,62}$). It defaults to the slugified name
campus.buildings[]campusbuilding slugs in map order (each a kind: building document), or inline building bodies
mode · managercampus, buildingwho decides at the doors (user:<id> or team:<id>); a building overrides the campus
building.campusbuilding documentthe campus slug it stands on; it must equal the campus that lists it
location · projectbuildingcloud or local; project is for local buildings only
policy.tiers · policy.gates · policy.budgetbuildingthe standard (code or action), a per-gate require / auto / tiered, and day_usd / item_usd hard stops
floors[].offices[]buildingoffice names (saved workflows, runner words in a local building, or inline {name, workflow})
intake[]building{api: true} (the items route), {bot: <saved bot>}, {schedule: <cron>, office: <office>}
pipeline[]buildingin order: {office}, {type: parallel|sequential, id, offices}, {gate}, {then: <building>} (last only)

A document may not name machines or credentials: node, path, bindings, api_key, token, secret, service, worker, url, endpoint and the like are refused, and an unknown key is refused with its path. The full grammar is orchestration/company-service/README.md.

curl -s -X POST https://api.plungeai.com/v1/workflows \
  -H "Authorization: Bearer $PLUNGE_API_KEY" -H 'Content-Type: application/json' \
  -d "$(jq -n --arg y "$(cat campus.yaml)" '{name:"plan-docs-…", kind:"campus", yaml:$y}')"
# → 201 {"workflow":{"id":"…","name":"plan-docs-…","kind":"campus","description":null,"folder":null,"updated_at":…,"version":null}}

17.3 Apply

Apply reads your saved documents, compiles them and stores the plan. It also saves any inline office as a workflow. Apply again after you edit a document; an inline office the new plan no longer names is deleted.

curl -s -X POST https://api.plungeai.com/v1/companies/plan-docs-…/apply \
  -H "Authorization: Bearer $PLUNGE_API_KEY"
# → 200 {"campus":"plan-docs-…","buildings":[{"slug":"desk","location":"cloud","offices":1}],
#        "workflows":[{"name":"plan-docs-…/desk/draft","id":"…","action":"created"}],
#        "schedules":[],"local":[],"warnings":[]}

A document set that does not compile is 422 compile_failed, with every path: message in the message. No saved campus document with that slug is 404 company_not_found. An inline office whose saved name (<campus>/<building>/<office>) is already taken by an agent or a bot is 409 office_conflict (orchestration/company-service/docs.ts).

List and layout are read-only:

curl -s https://api.plungeai.com/v1/companies -H "Authorization: Bearer $PLUNGE_API_KEY"
# → 200 {"companies":[…,{"slug":"plan-docs-…","name":"plan-docs-…","mode":"supervised","status":"applied",
#        "applied_at":"2026-10-14T00:29:15.962Z","buildings":1,"pending":0},…]}
curl -s https://api.plungeai.com/v1/companies/plan-docs-…/layout -H "Authorization: Bearer $PLUNGE_API_KEY"
# → 200 {"campus":{"slug":"plan-docs-…","mode":"supervised","manager":null,…},
#        "buildings":[{"slug":"desk","location":"cloud","mode":"supervised",
#          "policy":{"rubric":"action","gates":{"brief":"tiered","tool_permission":"tiered","content":"tiered",
#                    "commitment":"tiered","release":"tiered"},"budget":{"day_usd":null,"item_usd":null}},
#          "intake":[{"api":true}],
#          "pipeline":[{"id":"gate:brief","kind":"gate","gate":"brief"},
#                      {"id":"draft","kind":"office","offices":["draft"],"retry":null,"skip":null}],
#          "connected":true,…}],
#        "offices":[{"building":"desk","slug":"draft","name":"plan-docs-…/desk/draft","floor":"1","order":0,"source":"inline"}]}

17.4 Start

curl -s -X POST https://api.plungeai.com/v1/companies/plan-docs-…/start -H "Authorization: Bearer $PLUNGE_API_KEY"
# → 200 {"status":"running"}

Once the clock is started, cloud buildings walk their items. An office step starts an engine run, which is paid like any other run. stop disarms the clock; items keep their step and wait (17.7).

17.5 Items

curl -s -X POST https://api.plungeai.com/v1/companies/plan-docs-…/items \
  -H "Authorization: Bearer $PLUNGE_API_KEY" -H 'Content-Type: application/json' \
  -d '{"building":"desk","title":"Launch note","body":"One line for the launch.","kind":"content"}'
# → 201 {"id":"…","campus":"plan-docs-…","building":"desk","title":"Launch note","body":"One line for the launch.",
#        "kind":"content","source":"api","priority":0,"tier":null,"step":"intake","attempt":0,"status":"active",
#        "parked_reason":null,"paused":0,"steer":null,"last_output":null,"cost_usd":0,"parent_item_id":null,…}
FieldRule
buildinga building slug of this campus (required)
title1 to 300 characters (required)
bodytext, up to 65,536 characters
kindfeature, bugfix, docs, research, content or task
prioritya whole number
tiera tier word of the standard (T0…T3, V0…V3), up to 32 characters; without it the standard's default

Any other field is 422 invalid_params (unknown field: …). The snapshot shows where the item is. In the walk below it is waiting at the gate, and its approval is in the queue:

curl -s https://api.plungeai.com/v1/companies/plan-docs-…/snapshot -H "Authorization: Bearer $PLUNGE_API_KEY"
# → 200 {"head_seq":4,"mode":"supervised","status":"running",
#        "buildings":[{"slug":"desk","location":"cloud","connected":true,"mode":"supervised","active":1}],
#        "offices":[{"building":"desk","office":"draft","state":"idle","item_id":null}],
#        "items":[{"id":"…","title":"Launch note","step":"gate:brief","attempt":0,"status":"active",…}],
#        "queue":[{"id":"…","item_id":"…","step":"gate:brief","gate":"brief","tier":"V2","status":"pending",…}],
#        "truncated":false,"spend_today_usd":0,"shipped_7d":0}

The five item actions are POST …/items/{id}/<action>. Each answers the item as it is now:

ActionEffect
pausethe item keeps its step and is not walked until resumed
resumea paused or parked item goes on at the step it stopped on (a parked item starts a fresh visit)
retrythe step starts again as attempt + 1, or at the pipeline's retry target
cancelthe item ends failed with parked_reason: cancelled; running office runs are not interrupted
steer{text} (1 to 2,000 characters after trimming): a note the next office run receives once. A blank or longer text is 422 invalid_params

A cancelled item (status: failed) refuses pause and resume with 409 item_failed; retry it instead. Any action on a finished item is 409 item_done (orchestration/company-service/company-service.ts). This walk did not call the five actions. The live oracle tests/live/companies/items-actions.mjs runs all five against the deployed API on a local building of its own.

17.6 Approvals: the door

When an item reaches a gate that asks a person, the gate opens an approval. In supervised mode every gate asks.

curl -s "https://api.plungeai.com/v1/companies/plan-docs-…/approvals?status=pending" \
  -H "Authorization: Bearer $PLUNGE_API_KEY"
# → 200 {"approvals":[{"id":"…","item_id":"…","building":"desk","step":"gate:brief","gate":"brief","tier":"V2",
#        "status":"pending","payload_json":"{\"summary\":\"brief: Launch note\"}","execution_id":null,
#        "requested_at":"2026-10-14T00:29:18.611Z","expires_at":"2026-10-16T00:29:18.304Z",
#        "decided_at":null,"decided_by":null,"note":null}]}
curl -s -X POST https://api.plungeai.com/v1/companies/plan-docs-…/approvals/… \
  -H "Authorization: Bearer $PLUNGE_API_KEY" -H 'Content-Type: application/json' \
  -d '{"decision":"reject","note":"Docs walk: nothing to run."}'
# → 200 {"approval":{"id":"…","item_id":"…","step":"gate:brief","gate":"brief","tier":"V2","status":"rejected",
#        "execution_id":null,"decided_at":"2026-10-14T00:29:19.573Z","decided_by":"user:…",
#        "note":"Docs walk: nothing to run.",…}}

approve moves the item on to the next step, and reject parks it (parked_reason: rejected). A gate approval has execution_id: null. A tool permission is different: an office run paused to ask for a tool. Approving it also continues that execution once and hands its result back to the item. The answer then adds execution_id and continued: true, or continued: false with a continue_error (not_paused, session_expired, execution_not_found, continue_failed). The decision stands either way. Rejecting a tool permission leaves the run paused. A body other than {decision: approve|reject, note?} is 422 invalid_params.

17.7 Stop and delete

DELETE refuses a running company:

curl -s -X DELETE https://api.plungeai.com/v1/companies/plan-docs-… -H "Authorization: Bearer $PLUNGE_API_KEY"
# → 409 {"error":{"code":"conflict","message":"company \"plan-docs-…\" is running — stop it first"}}
curl -s -X POST https://api.plungeai.com/v1/companies/plan-docs-…/stop -H "Authorization: Bearer $PLUNGE_API_KEY"
# → 200 {"status":"stopped"}

curl -s -o /dev/null -w '%{http_code}\n' -X DELETE https://api.plungeai.com/v1/companies/plan-docs-… \
  -H "Authorization: Bearer $PLUNGE_API_KEY"
# → 204

curl -s https://api.plungeai.com/v1/companies/plan-docs-…/snapshot -H "Authorization: Bearer $PLUNGE_API_KEY"
# → 404 {"error":{"code":"company_not_found","message":"no company \"plan-docs-…\""}}

Delete removes every company row at once: buildings, offices, items, runs, approvals, the event log and the manifest. It does not remove your saved documents (the campus document and the inline offices saved as <campus>/<building>/<office>). Find them with GET /v1/workflows?search=<slug> and delete each one with DELETE /v1/workflows/{id} → 204 (16.1). The walk did this for both of its documents, and afterwards the search listed none and GET /v1/companies no longer listed the campus.

17.8 Mode, events and local buildings

PUT …/mode takes {mode} and switches the whole campus live, from the next tick. It overrides the campus and every building, a building's documented mode included, and it survives apply. Setting the campus's documented mode clears the override. A missing or unknown mode is 422 invalid_params. GET …/events answers a JSON page of the log after since (a seq). With Accept: text/event-stream or ?stream=1 it is a live feed of id: <seq>, event: <type>, data: <row>. A local building's node uses two more routes with the owner's key: GET …/buildings/{building}/slice, which returns the building's compiled pipeline, policy, project and office ids, and POST …/events ({events: [{building, type, item_id?, office?, data?, at?}]}, 1 to 200 events) to report back. This walk did not call these four routes. Their rules are in routes/companies.ts and routes/companies-events.ts.

17.9 Errors

StatusCodeWhen
400invalid_formatformat= is not json, yaml, markdown or text
404company_not_foundno campus with that slug for this key, or a slug that cannot be one (answered without a lookup)
404building_not_found · item_not_found · approval_not_foundno such building, item or approval in this company
409conflictDELETE while the company runs: stop it first
409item_failed · item_donepause or resume of a cancelled item (retry it); any action on a finished item
409approval_not_pendingdeciding an approval that is already decided or expired
409office_conflictapply: an inline office's saved name is taken by an agent or a bot
422invalid_paramsan item, decision, mode, steer or events body that breaks its rule; the message names the field
422compile_failedapply: the documents do not compile; the message lists each path: message
503not_enabledthe deployment has no company service
curl -s https://api.plungeai.com/v1/companies/no-such-campus/layout -H "Authorization: Bearer $PLUNGE_API_KEY"
# → 404 {"error":{"code":"company_not_found","message":"no company \"no-such-campus\""}}
curl -s -X POST https://api.plungeai.com/v1/companies/plan-docs-…/items \
  -H "Authorization: Bearer $PLUNGE_API_KEY" -H 'Content-Type: application/json' -d '{"building":"desk"}'
# → 422 {"error":{"code":"invalid_params","message":"title must be 1-300 characters"}}

The same operations are in the API reference under Companies, one page per route.

Planned: TI-34

The docs assistant is not available yet. You can hand these docs to your own assistant instead.