Platform Specification

The CLI

One CLI for both agents and humans. Designed so agents can work fluently and humans can set things up, observe, and intervene without friction. Every detail rethought from first principles.

Design Principles

Why the CLI works the way it does

One CLI, two audiences

Agents and humans use the same oc command. Agents use it to act, check permissions, store memories. Humans use it to connect integrations, manage trust, observe sessions, and approve requests. Same tool, different verbs.

Short commands, deep capabilities

Most commands are one or two words. oc do, oc find, oc can, oc recall. Every token an agent types costs compute. The CLI respects that.

Permissions are integrated, not separate

When an agent runs oc do, the permission check happens automatically. If approval is needed, the agent waits inline. No separate "check then act" workflow unless the agent wants one.

Trust grows, friction decreases

The first session requires explicit permissions. Over time, permissions accumulate and modes upgrade from approve to auto as trust is earned. The agent works with less interruption. The system gets out of the way.

Installation
# In a hosted session, oc is pre-installed and authenticated.
# For local use:
curl -fsSL https://opencompany.dev/install.sh | sh
oc login  # Opens browser for OAuth

# Or with a token
export OC_TOKEN="oc_live_..."

# All commands support --json for machine-readable output.

The Permission Model

The core of how trust works between humans and agents

The syntax

Every permission follows one pattern:

namespace:verb:resourcemode: auto | approve

Read it as: "on [namespace], [verb] the [resource]." The verb comes before the resource because it follows natural English order and because resources are hierarchical paths — placing them last means wildcards read cleanly from left to right.

Grammar rules:

  • Separators: : separates namespace, verb, and resource. / separates hierarchy within resources.
  • Actions (what you invoke) are namespace:verb — e.g. github:merge, slack:send
  • Permissions (what you hold) are namespace:verb:resource — e.g. github:merge:acme/api/pulls/456
  • Resource paths use / for hierarchy: org/repo/type/instance
  • Wildcards: * matches any single segment. Applied to verb or any resource segment.
  • Mode: Every permission is granted with a mode — auto (just do it) or approve (ask the human first). Mode is part of the grant, not a separate policy.
Examples
# Specific
github:read:acme/api/pulls/456          # read one PR
slack:send:#engineering                  # send to one channel
stripe:read:charges/ch_abc123           # read one charge

# Wildcards on resource (most common)
github:read:acme/api/*                  # read anything in a repo
github:read:acme/*                      # read anything in an org
slack:send:*                            # send to any channel
stripe:read:*                           # read any Stripe resource

# Wildcards on verb
github:*:acme/api/pulls/456             # do anything to one PR
slack:*:#engineering                    # do anything in one channel

# Broad
github:read:*                           # read anything on GitHub
github:*:*                              # full GitHub access
platform:*:*                            # all platform compute actions
*:*:*                                   # unrestricted (admin only)

Why this order?

namespace:verb:resource was chosen over namespace:resource:verb for three reasons:

  1. Natural language: "github: read from acme/api" reads better than "github: acme/api: read."
  2. Hierarchical resources stay at the end: Resources often have path structure (acme/api/pulls/456). Placing them last means wildcards expand naturally: acme/api/* acme/* *.
  3. Grouping by intent: When listing permissions, you see what actions are available first, then where. "I can read from these three repos" is more useful than "in this repo, I can do these three things."

How matching works

When an action is invoked, the platform gateway resolves the target resource from the arguments and checks if any permission matches. This happens at the gateway before credentials are injected — no permission, no outbound request. A permission matches if every segment is equal or wildcarded.

Permission matching
# Agent runs:
oc do github:comment --repo acme/api --pr 456 --body "LGTM"

# Platform resolves target: github:comment:acme/api/pulls/456
# Checks permissions in order:

github:comment:acme/api/pulls/456   → exact match ✓
github:comment:acme/api/*           → wildcard match ✓
github:comment:acme/*               → wildcard match ✓
github:*:acme/api/*                 → wildcard match ✓
github:comment:*                    → wildcard match ✓
*:*:*                               → wildcard match ✓

github:read:acme/api/*              → verb mismatch ✗
github:comment:other-org/*          → resource mismatch ✗

Permission lifetime

Every permission has an expiry. There are two values that matter:

never

Persists until explicitly revoked. Included in every future session. Represents earned trust. Granted by humans via oc trust grant.

session end

Disappears when the session ends. Useful for one-off elevated access. Granted at spawn time or via mid-session approval.

When a session starts, the agent receives all its never-expiry permissions plus any session-specific grants. Over time, as humans grant more persistent permissions, sessions start with broader access and less friction.

Managing permissions (human side)
# Grant a persistent permission (expires: never)
$ oc trust grant code-reviewer github:read:acme/* --mode auto
✓ Permission granted (auto, never)

# Grant with approve mode
$ oc trust grant code-reviewer github:merge:acme/api/* --mode approve
✓ Permission granted (approve, never)

# View an agent's trust profile
$ oc trust show code-reviewer

Agent:  code-reviewer
Trust:  established (47 sessions, 0 incidents)

PERMISSION                          MODE      DELEGATABLE  EXPIRES
github:read:acme/*                  auto      yes          never
github:comment:acme/*               auto      yes          never
github:merge:acme/api/*             approve   no           never
slack:send:#engineering             auto      yes          never
slack:read:*                        auto      yes          never
platform:*:*                        auto      yes          never

# Upgrade mode (trust has been earned)
$ oc trust grant code-reviewer github:merge:acme/api/* --mode auto
✓ Permission updated: approve → auto

# Revoke
$ oc trust revoke code-reviewer github:merge:acme/api/*
✓ Permission revoked

Mode: the two ways to hold a permission

Every permission is granted with a mode. Mode is not a separate policy layer — it's part of the permission itself. Think of it like managing an intern: you might give them permission to merge PRs but tell them to check with you each time. The permission and the oversight are one decision.

auto

Agent acts freely. No human in the loop. For actions you trust the agent to handle independently.

"You can read any file in the repo — just do it."

approve

Agent has the authority, but must get sign-off each time. The human sees the specific action, context, and reasoning before it executes.

"You can merge PRs, but run each one by me."

Why not three modes?

No "first-use" or "auto-after-one-approval." The permission model should be obvious: either you trust the agent to act or you want to see each action. If after a few approvals you decide the agent handles it well, upgrade the mode to auto. That's an explicit trust decision, not an automatic escalation.

The result: When you look at an agent's permissions, you see exactly what it can do and how. No separate policy table to cross-reference. The permission is the policy.

Trust escalation

Trust is not a static property. It changes based on track record. The platform tracks agent behavior and surfaces trust level to humans, making it easy to decide when to grant or upgrade permissions.

1

New

Few permissions, most in approve mode. Reads might be auto, everything else requires sign-off. Human reviews output carefully.

2

Established

More permissions granted. Familiar actions upgraded from approve to auto. New domains and high-risk actions still in approve.

3

Trusted

Wide permissions, mostly auto. Only genuinely dangerous actions — production deploys, financial transactions — remain in approve. The agent works with minimal interruption.

Trust grows two ways: granting new permissions, and upgrading existing ones from approve to auto. Both are explicit human decisions. The platform suggests upgrades but humans always decide.

Checking permissions (agent side)

oc can — check before acting
# Do I have this permission?
$ oc can github:read:acme/api/pulls/456
✓ Allowed (auto — via github:read:acme/*)

# What about this?
$ oc can github:merge:acme/api/pulls/456
⏳ Allowed with approval (approve — via github:merge:acme/api/*)

# And this?
$ oc can stripe:create:charges/new
✗ No permission — request it with: oc request stripe:create:charges/new

# List everything I have
$ oc permissions

PERMISSION                          MODE      DELEGATABLE  EXPIRES
github:read:acme/*                 auto      yes          never
github:comment:acme/*              auto      yes          never
github:merge:acme/api/*            approve   no           never
slack:send:#engineering             auto      yes          never
slack:read:*                       auto      yes          never
platform:*:*                       auto      yes          never
oc request — ask for what you don't have
# Request a permission mid-session
$ oc request stripe:read:charges/* \
    --reason "Customer asked about recent charges, need to look them up"

Request submitted: req_abc123
Waiting for approval from louis... (timeout: 5m)
✓ Approved by louis (23s)

Permission granted: stripe:read:charges/* (auto, session end)

# The human saw this and had four choices:
#   1. "Approve (this session)"     → auto, expires: session end
#   2. "Approve (persist, auto)"    → auto, expires: never
#   3. "Approve (persist, approve)" → approve, expires: never
#   4. "Deny"                       → agent gets an error

How permissions are remembered

Every approval decision is stored. The platform builds a history of what's been requested, granted, and denied. This serves three purposes:

Mode upgrades are informed. When an agent has been approved 10 times for the same permission, the platform surfaces this: "Consider upgrading to auto." The human sees the history and decides.

Trust profiles are accurate. Session count, approval rate, incident history — all tracked and surfaced to humans when they're deciding about new permissions and mode upgrades.

Agents learn the landscape. When an agent is denied, the reason is stored. Future sessions can recall why a permission was denied and adjust their approach.

Actions

Finding things to do, then doing them

oc do — execute an action

The command agents use most. Every oc do routes through the platform gateway, which handles the full lifecycle: permission check, approval flow (if needed), credential injection, execution against the external API, audit logging, and verification. One call, everything handled.

Simple action (permission already held)
$ oc do slack:send --channel "#engineering" --message "Build failed on main"

✓ slack:send:#engineering (auto)
✓ Sent (msg_abc123, 89ms)

{
  "message_id": "msg_abc123",
  "channel": "#engineering",
  "timestamp": "2025-01-22T14:30:01Z"
}
Action requiring approval (inline)
$ oc do github:merge --repo acme/api --pr 456 --method squash

⏳ github:merge:acme/api/pulls/456 (approve)
   Requesting approval from louis... (timeout: 5m)
   Notified via: push, slack

✓ Approved by louis (8s)
✓ Merged (sha: abc123def)

{
  "merged": true,
  "sha": "abc123def456",
  "method": "squash"
}
Action denied
$ oc do stripe:create --type refund --charge ch_abc --amount 5000

⏳ stripe:create:refunds/ch_abc (approve)
   Requesting approval from louis... (timeout: 5m)

✗ Denied by louis: "Check with finance team first — amount over $20"
Error: Permission denied for stripe:create:refunds/ch_abc

# The denial reason is stored. Future sessions can recall it:
# oc recall "stripe refund denials" → "Amounts over $20 need finance approval"
Approval timeout
$ oc do github:merge --repo acme/api --pr 789

⏳ github:merge:acme/api/pulls/789 (approve)
   Requesting approval from louis... (timeout: 5m)

✗ Approval timed out (5m). Session clock was paused during wait.
Error: No response for github:merge:acme/api/pulls/789

Hint: Louis can still approve later: oc approve req_abc123

Session clock pauses during approval waits

If a session has a 5-minute budget and the agent waits 3 minutes for approval, the session still has 5 minutes of work time left. Approval wait time is not charged against the budget. The agent is not consuming resources while waiting.

Anti-abuse limits

  • Max pending requests: 3 concurrent approval requests per session. A 4th blocks until one resolves.
  • Wall-clock timeout: Sessions have an independent wall-clock limit (default: 30 minutes) regardless of session-clock pausing. Prevents indefinite blocking workflows.
  • Request rate limit: Max 10 approval requests per session. After that, additional requests are auto-denied.

oc find — discover actions by intent

Agents don't always know the action name. They know what they want to accomplish. oc find takes natural language and returns matching actions, ranked by relevance, with permission status.

oc find
$ oc find "notify the team about a build failure"

ACTION               RELEVANCE  PERMISSION STATUS
slack:send           0.95       ✓ auto (slack:send:*)
email:send           0.82       ✗ integration not connected
github:create        0.45       ✓ approve (github:create:acme/*/issues)

# With detail
$ oc find "notify the team" --detail

1. slack:send (0.95)
   Permission:  ✓ auto (slack:send:*)
   Cost:        free
   Input:       channel (string, required)
                message (string, required)
                thread_ts (string, optional)
   Output:      message_id, channel, timestamp

2. email:send (0.82)
   Permission:  ✗ integration not connected
   Setup:       oc connect email
   Cost:        free

Verification and rollback

Every action returns verification data — proof that it worked — and rollback information where applicable. Because all actions route through the platform gateway, verification is captured at the infrastructure level, not self-reported by the agent. This is what makes it possible to audit outcomes, not just intentions.

Full response with --verbose
$ oc do slack:send --channel "#engineering" --message "PR #456 merged" --verbose

{
  "action": "slack:send",
  "status": "success",
  "output": {
    "message_id": "msg_abc123",
    "channel": "C0123ABCD",
    "timestamp": "1705934400.000100"
  },
  "verification": {
    "method": "api_response",
    "status_code": 200,
    "confirmed": true,
    "verified_at": "2025-01-22T14:30:01Z"
  },
  "rollback": {
    "action": "slack:delete",
    "args": { "channel": "C0123ABCD", "timestamp": "1705934400.000100" },
    "permission_needed": "slack:delete:#engineering"
  },
  "cost": { "cents": 0 },
  "duration_ms": 89,
  "permission_used": "slack:send:* (auto)"
}

oc actions — list what's available

oc actions
$ oc actions

NAMESPACE   ACTION          TYPE          COST
github      read-pr         integration   free
github      comment         integration   free
github      review          integration   free
github      merge           integration   free
github      create-issue    integration   free
slack       send            integration   free
slack       read            integration   free
stripe      read            integration   free
stripe      create          integration   free
platform    summarize       compute       ~$0.02
platform    embed           compute       ~$0.001
platform    web-scrape      paid          ~$0.05

# Filter by namespace
$ oc actions --namespace github

Memory

What persists, how it's stored, how it's found

oc remember — store a memory

Memory lives at the platform level, not inside sessions. When you store a memory, it goes to the platform's memory store, tagged with a scope. When you search, the platform checks your memory:read permissions and only returns memories you're allowed to see.

Simple (auto-classified)
$ oc remember "Louis prefers tabs over spaces"
✓ Stored as fact (scope: user:louis, confidence: 0.9)

$ oc remember "Deploy failed — missing DB migration on the payments table"
✓ Stored as episode (scope: project:acme/api, confidence: 1.0)

$ oc remember "Always check for SQL injection when reviewing user input handlers"
✓ Stored as procedure (scope: project:acme/api, confidence: 0.85)
Explicit
$ oc remember "The auth system uses JWT with 1h expiry and refresh tokens" \
    --type fact \
    --scope project:acme/api \
    --confidence 0.95

✓ Stored: mem_abc123

$ oc remember "Jan 22: Reviewed and merged PR #456, found SQL injection" \
    --type episode \
    --tags security,pr-review \
    --outcome success

✓ Stored: mem_def456

Memory types

fact

Something true. May become stale. Confidence decays over time unless reinforced.

episode

Something that happened. Immutable. Timestamped. Context may shift in relevance but the event itself is permanent.

procedure

How to do something. A learned pattern. Strengthened by repetition, weakened by disuse.

oc recall — search memory

Semantic search by default. Describe what you're looking for in natural language and the platform returns relevant memories, ranked by a combination of relevance, recency, and confidence. Stale or contradicted facts are flagged.

Semantic search
$ oc recall "deployment process"

TYPE       AGE     CONFIDENCE  CONTENT
fact       2w      0.90        Deploy target is Vercel
procedure  1mo     0.85        Always run e2e tests before deploying
episode    3mo     -           Mar 15: Deploy failed, missing DB migration
fact       1y      0.40        Deploy target is Heroku
                               ↳ STALE — contradicted by newer fact
Filtered search
# By type
$ oc recall "testing" --type procedure

# By scope
$ oc recall "deployment" --scope project:acme/api

# By recency
$ oc recall "decisions" --since 7d

# By type, scope, and recency combined
$ oc recall "auth" --type fact --scope project:acme/api --since 30d
Get a specific memory
$ oc recall mem_abc123

{
  "id": "mem_abc123",
  "type": "fact",
  "content": "The auth system uses JWT with 1h expiry and refresh tokens",
  "scope": "project:acme/api",
  "confidence": 0.95,
  "created": "2025-01-22T14:30:00Z",
  "created_by": "sess_xyz789",
  "last_accessed": "2025-01-24T10:15:00Z",
  "access_count": 7,
  "reinforced_by": ["sess_abc111", "sess_abc222"]
}

Access control

Memory access uses the same permission model as everything else. No special --memory-scope flag — memory permissions are granted like any other permission.

memory:read:org/acmeCan read org-wide memories (shared across workspaces).
memory:read:workspace/engineeringCan read workspace-scoped memories.
memory:read:project/acme/apiCan read this project's memories.
memory:write:project/acme/apiCan store memories to this project.
memory:read:user/louisCan read this user's memories.

Scope hierarchy: org > workspace > project > user > session. Memories are visible to agents whose permissions cover the scope.

When oc recall runs, the platform checks the session's memory:read:* permissions and only returns memories from accessible scopes. When oc remember runs, it checks memory:write:*. Same gateway, same enforcement, same audit trail.

Confidence and decay

Facts become stale. A deployment target recorded a year ago might have changed. The platform handles this through confidence decay and reinforcement:

  • -Facts lose confidence over time unless accessed or reinforced.
  • -When a fact is confirmed by a new session, its confidence resets upward.
  • -When a new fact contradicts an old one, the old one is flagged as stale.
  • -Procedures strengthen with repetition and weaken with disuse.
  • -Episodes are immutable — they happened. But their relevance to current search is ranked by recency.
oc forget — remove a memory
$ oc forget mem_abc123
✓ Removed: "Deploy target is Heroku" (fact, was already stale)

# Forget by content match
$ oc forget --match "Heroku"
Found 2 memories matching "Heroku". Remove all? (y/n)

Sessions & Delegation

The execution context and how work gets distributed

oc status — where am I, what can I do

The first thing an agent sees when a session starts. One command, everything you need to orient: task, budget, permissions. Memory access is visible in the permissions list.

oc status
$ oc status

SESSION    sess_abc123
ORG        acme
WORKSPACE  engineering
TASK       Review PR #456 for security issues
PARENT     louis (human)
AGENT      code-reviewer (v2.0)
BUDGET     $5.00 remaining · 5:00 remaining

PERMISSIONS (7)
  github:read:acme/*              auto      never
  github:comment:acme/*           auto      never
  github:merge:acme/api/*         approve   never
  slack:send:#engineering          auto      never
  slack:read:*                    auto      never
  platform:*:*                    auto      never
  spawn:*                         auto      never      delegatable
  memory:read:project/acme/api    auto      never
  memory:read:user/louis          auto      never
  memory:write:project/acme/api   auto      session end
oc status --json (for programmatic use)
{
  "session_id": "sess_abc123",
  "org": "acme",
  "workspace": "engineering",
  "status": "active",
  "task": "Review PR #456 for security issues",
  "parent": { "type": "human", "id": "louis" },
  "agent": { "id": "code-reviewer", "version": "2.0" },
  "budget": {
    "cost": { "used_cents": 0, "limit_cents": 500 },
    "time": { "used_seconds": 0, "limit_seconds": 300 }
  },
  "permissions": [...]
}

Spawning sessions

Sessions are created by humans or by other agents. A human spawns the initial session. That agent can spawn sub-sessions with narrower scope.

Human spawns a session
$ oc spawn code-reviewer \
    --task "Review PR #456 for security issues" \
    --permission "github:merge:acme/api/pulls/456 --mode approve" \
    --budget 500 \
    --timeout 300

Session: sess_abc123
Agent:   code-reviewer (v2.0)
Status:  active

# Persistent permissions (expires: never) are automatically included.
# The --permission flag adds session-scoped permissions on top.

# Watch it work
$ oc watch sess_abc123

# Or get the result when done
$ oc result sess_abc123 --wait
Agent spawns a sub-session
# From inside my session:
$ oc spawn security-reviewer \
    --task "Check PR #456 for SQL injection in user input handlers" \
    --permission "github:read:acme/api/pulls/456" \
    --permission "memory:read:project/acme/api" \
    --budget 50 \
    --timeout 60 \
    --wait

Spawning sub-session...
Session: sess_sub_789
Agent:   security-reviewer (v1.0)
Parent:  sess_abc123 (me)

Waiting for result...

{
  "session_id": "sess_sub_789",
  "status": "completed",
  "duration_seconds": 42,
  "cost_cents": 18,
  "output": {
    "findings": [
      {
        "severity": "high",
        "file": "src/api/users.ts",
        "line": 45,
        "issue": "Unsanitized user input in SQL query",
        "recommendation": "Use parameterized queries"
      }
    ]
  }
}

Delegation constraints

  • - I can only delegate permissions I have AND that are marked delegatable.
  • - Sub-session budget cannot exceed my remaining budget.
  • - Sub-session actions count against my budget.
  • - The trust chain only narrows. A sub-session can never have more access than its parent.
  • - Max spawn depth: 3 levels (human → agent → sub-agent → sub-sub-agent). Prevents recursive spawning.
  • - Max concurrent sub-sessions: 5 per parent. Total sub-session tree capped at 20 per root session.

Managing sub-sessions

oc agents
# List my sub-sessions
$ oc agents

ID            STATUS     AGENT               COST    DURATION
sess_sub_789  completed  security-reviewer    $0.18   42s
sess_sub_abc  active     summarize            $0.03   8s
sess_sub_def  failed     test-runner          $0.12   60s (timeout)

# Get result
$ oc result sess_sub_789
{ "findings": [...] }

# Kill a running sub-session
$ oc kill sess_sub_abc

Lifecycle

spawned
active
completed | failed | timeout | killed

A session ends when the agent completes its task, hits a budget limit, times out, encounters an unrecoverable error, or is killed by a human. Memories stored during the session already live at the platform level — nothing needs to be "saved." The session log is finalized for audit.

Human Interface

Setup, observation, approval, intervention

oc connect — set up integrations

Integrations are connected at the platform level. Credentials (OAuth tokens, API keys) are stored platform-side and never exposed to agent sessions. When an agent takes an action, the platform gateway injects the real credentials into the outbound request.

Connecting integrations (credentials stored platform-side)
# OAuth flow (opens browser)
$ oc connect slack
Opening browser for OAuth...
✓ Slack connected (workspace: Acme Inc)
  Credentials: stored platform-side (never exposed to sessions)
  Actions available: slack:send, slack:read, slack:react, slack:list

# API key
$ oc connect stripe --key sk_live_abc123
✓ Stripe connected
  Credentials: stored platform-side (never exposed to sessions)
  Actions available: stripe:read, stripe:create, stripe:update

# Token
$ oc connect github --token ghp_abc123
✓ GitHub connected (user: louis)
  Credentials: stored platform-side (never exposed to sessions)
  Actions available: github:read-pr, github:comment, github:review,
                     github:merge, github:create-issue, github:read-repo

# List integrations
$ oc integrations

INTEGRATION  STATUS     ACTIONS  CONNECTED   CREDENTIAL
slack        connected  4        louis        OAuth token (platform-stored)
github       connected  7        louis        OAuth token (platform-stored)
stripe       connected  4        louis        API key (platform-stored)

Why platform-stored credentials?

Sessions never hold external credentials. All actions route through the platform gateway, which injects credentials at request time. This means: a compromised session can't leak tokens, permissions can be revoked instantly (takes effect on the next request), and every action is audited at one central point.

Observation — watch and log

oc watch — live activity stream
$ oc watch sess_abc123

14:30:01 ▸ Session started (code-reviewer v2.0, budget: $5/5m)
14:30:02 ▸ memory:read project/acme/api (14 facts, 4 episodes, 2 procedures)
14:30:03 ▸ github:read-pr acme/api #456 ✓ (234ms)
14:30:05 ▸ platform:summarize (4 files, 1847 lines) ✓ (1.2s, $0.02)
14:30:07 ▸ Spawned: security-reviewer → sess_sub_789
14:30:49 ▸ Sub-session completed ($0.18, 42s) — 1 finding
14:30:50 ▸ github:comment acme/api #456 ✓ (156ms)
14:30:51 ▸ slack:send #engineering ✓ (89ms)
14:30:52 ▸ github:merge acme/api #456 ⏳ awaiting approval
14:31:00 ▸ github:merge acme/api #456 ✓ approved by louis
14:31:01 ▸ Memory stored: episode "Reviewed PR #456, found SQL injection"
14:31:02 ▸ Session completed ($0.43, 61s, 7 actions)
oc log — historical audit
$ oc log sess_abc123

SESSION  sess_abc123
AGENT    code-reviewer (v2.0)
PARENT   louis
STATUS   completed
DURATION 61s
COST     $0.43
ACTIONS  7

TIMELINE
  14:30:03  github:read-pr          acme/api #456       ✓  $0.00   234ms
  14:30:05  platform:summarize      4 files             ✓  $0.02   1.2s
  14:30:07  spawn                   security-reviewer   ✓  $0.18   42s
  14:30:50  github:comment          acme/api #456       ✓  $0.00   156ms
  14:30:51  slack:send              #engineering        ✓  $0.00   89ms
  14:31:00  github:merge            acme/api #456       ✓  $0.00   312ms
  14:31:01  memory:store            episode             ✓  -       -

PERMISSIONS USED
  github:read:acme/* (auto)
  github:comment:acme/* (auto)
  github:merge:acme/api/* (approve, approved at 14:31:00)
  slack:send:#engineering (auto)
  platform:*:* (auto)

MEMORIES CREATED
  episode: "Reviewed PR #456, found SQL injection in user input handler"

# JSON output for programmatic analysis
$ oc log sess_abc123 --json

Approval

When an agent needs approval, speed matters. The agent is blocked and waiting. The platform notifies humans through their configured channels — not just the CLI.

Notification channels

CLIoc pending — poll for pending requests
PushMobile notification with approve/deny actions
SlackDM with context and approve/deny buttons
EmailOne-click approve link for lower-urgency requests
CLI approval flow
# List pending requests
$ oc pending

ID          SESSION     ACTION                            AGE   REASON
req_abc     sess_123    github:merge:acme/api/pulls/456   12s   Review complete, all checks passing
req_def     sess_456    stripe:create:refunds/ch_789      2m    Customer requested refund ($15)

# Approve (this action only, session-scoped)
$ oc approve req_abc
✓ Approved: github:merge:acme/api/pulls/456

# Approve and persist (keeps approve mode — agent still checks in each time)
$ oc approve req_abc --persist
✓ Approved: github:merge:acme/api/pulls/456
✓ Permission persisted: github:merge:acme/api/pulls/456 (approve, never)

# Approve, persist, and upgrade to auto (full trust)
$ oc approve req_abc --persist --mode auto
✓ Approved: github:merge:acme/api/pulls/456
✓ Permission persisted: github:merge:acme/api/pulls/456 (auto, never)

# Deny with reason
$ oc deny req_def --reason "Check with finance team first"
✗ Denied: stripe:create:refunds/ch_789
Without --persist, the approval is session-scoped — it disappears when the session ends. With --persist, the permission lives forever (defaults to approve mode). Adding --mode auto says "I trust you to handle this from now on." To widen scope, use oc trust grant explicitly.

Intervention

Humans can intervene in any running session at any time. The controls are simple and non-destructive by default.

Session controls
# Pause (agent is suspended, can be resumed)
$ oc session pause sess_abc123
✓ Paused sess_abc123

# Resume
$ oc session resume sess_abc123
✓ Resumed sess_abc123

# Add budget mid-session
$ oc session budget sess_abc123 --add 200
✓ Budget updated: $2.12 / $7.00

# Revoke a permission mid-session
$ oc session revoke sess_abc123 slack:send:*
✓ Permission revoked. Agent will be notified on next action.

# Kill
$ oc session kill sess_abc123 --reason "No longer needed"
✓ Killed sess_abc123 (was active, 61s, $0.43)

Organization & Workspace

Everything operates within an organization and workspace. By default, org = workspace — no extra complexity until you need to subdivide for teams or departments.

Organization commands
# View current org info
$ oc org
Organization:  Acme Inc (acme)
Members:       louis (admin), alice (member)
Workspaces:    2 (engineering, support)
Billing:       Team plan
Integrations:  3 org-level (GitHub, Stripe, Datadog)

# Invite a member
$ oc org invite alice@acme.com --role member
✓ Invitation sent
Workspace commands
# List workspaces
$ oc workspace list
  NAME          AGENTS  INTEGRATIONS  MEMBERS
* engineering   4       5 (3 org + 2 workspace)   3
  support       2       4 (3 org + 1 workspace)   2

# Switch active workspace
$ oc workspace switch support
✓ Switched to workspace: support

# Create a new workspace
$ oc workspace create data-team
✓ Created workspace: data-team
  Inherits 3 org-level integrations

# View workspace details
$ oc workspace show engineering
Workspace:      engineering (default)
Org:            Acme Inc
Integrations:   5 (3 inherited from org + 2 workspace-level)
  org:  GitHub, Stripe, Datadog
  ws:   Slack #engineering, Jira
Agents:         code-reviewer, deploy-bot, test-runner, security-scanner
Active sessions: 2

Command Reference

Every command, at a glance

Agent commands
oc statusSession context: task, budget, permissions
oc do <action>Execute an action (permission check + approval inline)
oc find <query>Find actions by intent (natural language)
oc actionsList all available actions
oc can <permission>Check if a permission is held
oc request <perm>Request a permission (triggers approval flow)
oc permissionsList all current permissions
oc remember <content>Store a memory (requires memory:write permission)
oc recall <query>Search memories (semantic, filterable)
oc forget <id>Remove a memory
oc spawn <agent>Spawn a sub-session with narrower permissions
oc agentsList active sub-sessions
oc result <session>Get result from a completed sub-session
oc kill <session>Kill a running sub-session
Human commands
oc orgView organization info, members, billing
oc workspace listList workspaces in current org
oc workspace switch <n>Switch active workspace
oc workspace create <n>Create a new workspace
oc workspace show <n>View workspace details, integrations, agents
oc connect <name>Add an integration (OAuth, API key, or token)
oc integrationsList connected integrations
oc trust grant <a> <p>Grant permission (--mode auto|approve, expires: never)
oc trust revoke <a> <p>Revoke a permission
oc trust show <agent>View agent trust profile and all permissions with modes
oc spawn <agent>Start a new agent session
oc watch <session>Live activity stream
oc log <session>Historical session audit
oc pendingList pending approval requests
oc approve <id>Approve a request (optionally --persist --mode auto|approve)
oc deny <id>Deny a request (with --reason)
oc result <session>Get session result
oc session pause <id>Pause a running session
oc session resume <id>Resume a paused session
oc session budget <id>Adjust session budget
oc session revoke <id> <p>Revoke a permission mid-session
oc session kill <id>Kill a running session

All commands support --json for machine-readable output and --help for usage details.

A CLI that makes agents powerful and humans confident.
Minimal commands. Integrated permissions. Trust that grows.