Skip to content

eidos-agi/cept

cept — proprioception for coding agents

Short for proprioception. Cept is the agent's mirror.

Coding agents loop. They polish corners while the center is wrong. They retry the same fix three times instead of asking what they're missing. cept is a meta-tool that gives an agent a structured way to step back, look at its own recent trajectory, and request outside-in steering — through OpenRouter, defaulting to a model with web search baked in.

What it does

When invoked (explicitly via "use cept" or by an agent that has reached a decision point):

  1. Locate the active Claude Code session JSONL under ~/.claude/projects/<dashed-cwd>/.
  2. Slice the last N minutes of events (default 20).
  3. Distill raw events into a steering packet — decisions, attempts, errors, files touched, loops.
  4. Collect repo state — branch, dirty files, diff stat.
  5. Redact API keys, bearer tokens, env values, PEM blocks, emails, home paths.
  6. Ask an OpenRouter model (default perplexity/sonar-reasoning — reasoning + live web search) with a mode-specific prompt.
  7. Return a structured response: hypotheses, recommended next step, facts to verify, confidence.

Modes

Mode Use when
steer Default. Broad outside-in guidance, blind spots, next step.
debug Rank likely causes from evidence and errors.
research Find external facts, docs, version gotchas.
architecture Compare design alternatives and tradeoffs.

Install

cd cept
uv sync

Per-tree keys with .ceptkey

Drop a .ceptkey (preferred) or ceptkey file anywhere in your directory tree. Cept walks up from the working directory until it finds one, then loads it as dotenv. The file overrides process env — so if you have OPENROUTER_API_KEY exported in your shell but a .ceptkey in the project tree, the project key wins. That's the point: per-folder cost attribution and project-specific model defaults.

Easiest way is to use the bundled scaffold:

cept-keyfile init \
  --service openrouter \
  --name cept-djs-01 \
  --key sk-or-... \
  --model perplexity/sonar-reasoning \
  --scope "~/repos-eidos-agi/" \
  --notes "Eidos AGI shared key" \
  --path ~/repos-eidos-agi/.ceptkey

That writes a 0600-permissioned file with auto-populated provenance (created_at, created_on, created_by, created_os) plus the values you passed. Inspect at any time:

cept-keyfile show          # nearest keyfile, metadata only — no values
cept-keyfile where         # just the path

By hand it looks like:

# cept-meta:service=openrouter
# cept-meta:key_name=cept-djs-01
# cept-meta:created_at=2026-04-27T18:16:44+00:00
# cept-meta:created_on=daniels-mbp.local
# cept-meta:created_by=dev@example.com
# cept-meta:created_os=Darwin 24.3.0 (arm64)
# cept-meta:scope=~/repos-eidos-agi/
# cept-meta:notes=Eidos AGI shared key

OPENROUTER_API_KEY=sk-or-clientA...
CEPT_DEFAULT_MODEL=anthropic/claude-sonnet-4-5:online
CEPT_LOOKBACK_MINUTES=10

# cept-meta: lines are pure comments to anything that isn't cept (including source ./.ceptkey in your shell), but cept captures them as a metadata block surfaced in the result. Useful for auditing which key is which without leaking values.

Walk stops at the first match. Capped at $HOME when cwd is under home; otherwise capped at filesystem root. Add .ceptkey and ceptkey to your global gitignore so you never commit one by accident.

Recognized keys:

Key Effect
OPENROUTER_API_KEY OpenRouter credential.
OPENROUTER_REFERER Optional HTTP-Referer header for OpenRouter app rankings.
OPENROUTER_TITLE Optional X-Title header.
CEPT_DEFAULT_MODEL Per-tree default model (e.g. openai/gpt-5:online).
CEPT_LOOKBACK_MINUTES Per-tree default lookback window.

⚠️ Trust model: cept loads any .ceptkey it finds while walking up. If you cd into a hostile repo with a malicious .ceptkey, your packets would route to that endpoint. Blast radius is the redacted packet (no real key exfil), but be aware. v1 doesn't do direnv allow-style ceremony — just don't cd into untrusted trees.

Model selection (via OpenRouter)

cept uses OpenRouter as the gateway, so you can swap models without changing the client.

Model id Why
perplexity/sonar-reasoning (default) Reasoning + live web search. Best for steer/debug.
perplexity/sonar-pro Fast web search, no reasoning trace.
anthropic/claude-sonnet-4-5:online Claude with web search via OpenRouter (:online suffix).
openai/gpt-5:online GPT with web search.

Append :online to any compatible model name to force web search.

MCP server

Register with Claude Code:

// ~/.claude/claude_desktop_config.json (or equivalent MCP host config)
{
  "mcpServers": {
    "cept": {
      "command": "uv",
      "args": ["run", "--directory", "/absolute/path/to/cept", "cept"],
      "env": {
        "OPENROUTER_API_KEY": "sk-or-...",
        "OPENROUTER_TITLE": "cept",
        "OPENROUTER_REFERER": "https://github.com/eidos-agi/cept"
      }
    }
  }
}

The OPENROUTER_TITLE and OPENROUTER_REFERER env vars are optional — they show up on OpenRouter's app rankings.

Then in a Claude Code session: "use cept — I'm stuck on the OAuth callback."

CLI (dry-run / debugging)

# Distill the current session and print the redacted packet without calling OpenRouter:
cept-cli --goal "fix oauth callback" --dry-run

# Send for real:
OPENROUTER_API_KEY=sk-or-... cept-cli --goal "fix oauth callback" --mode debug

# Try a different model:
OPENROUTER_API_KEY=sk-or-... cept-cli --goal "..." --model "anthropic/claude-sonnet-4-5:online"

Design rules

  • Redact before send. Local secrets must never leave the machine.
  • Compress aggressively. The model gets signal, not raw logs.
  • Structured output. The agent consumes JSON fields, not prose.
  • Bounded. Hard caps on transcript size, lookback, event count.
  • Selective. Cept is an escalation tool, not a default tool.

Live progress (--emit) and the floating HUD

cept emits structured progress events at every phase boundary. Adapters consume them; you choose what surface you want.

# default: text events on stderr (stdout stays clean for the JSON result)
cept-cli --goal "..." --dry-run

# JSONL on stderr (machine-readable)
cept-cli --goal "..." --emit jsonl:stderr

# append to a log file
cept-cli --goal "..." --emit file:~/.cept/status.jsonl

# floating HUD panel (see below)
cept-cli --goal "..." --emit hud

# multiple at once: HUD + log
cept-cli --goal "..." --emit hud --emit file:~/.cept/status.jsonl

# silent
cept-cli --goal "..." --quiet

For the MCP server (where stdout is the JSON-RPC channel and must stay clean), set CEPT_EMIT in the server's env:

"env": {
  "OPENROUTER_API_KEY": "sk-or-...",
  "CEPT_EMIT": "hud,file:~/.cept/status.jsonl"
}

Adapter spec syntax

Spec What
stdout / stderr Human-readable text
jsonl:- / jsonl:stderr JSONL to stdout/stderr
jsonl:PATH / file:PATH Append JSONL to file
socket:PATH JSONL to a Unix domain socket (no-op if no listener)
subprocess:CMD Spawn CMD, write JSONL to its stdin
hud Spawn the bundled Swift HUD ($CEPT_HUD_CMD or cept-hud --once in $PATH)
notify macOS notification banners (skips noisy phases)
noop Drop everything

Event schema (the stable contract)

{
  "run_id": "abc123",
  "seq": 7,
  "ts": "2026-04-27T20:00:00.000Z",
  "phase": "asking_model",
  "level": "info",
  "msg": "asking perplexity/sonar-reasoning",
  "data": {"model": "perplexity/sonar-reasoning"}
}

Anyone can write a different consumer (dashboard, Slack bridge, log forwarder) by reading JSONL with this schema.

The HUD just works

--emit hud auto-builds the Swift binary on first use and caches it at ~/.cache/cept/cept-hud (or $XDG_CACHE_HOME/cept/cept-hud). First call costs ~5-10 seconds; subsequent calls are instant. You don't need to know Swift exists.

# First time: cept builds cept-hud, then runs.
cept-cli --goal "..." --emit hud

# Every time after: cache hit, no build, panel pops up.

Resolution order:

  1. $CEPT_HUD_CMD — full command override (e.g. for testing builds)
  2. $CEPT_HUD_BIN — path to a binary you already have
  3. cept-hud on $PATH
  4. ~/.cache/cept/cept-hud — auto-built and cached
  5. Build from hud/Package.swift next to the cept package — first-call cost

If none work (no Swift toolchain, source missing) --emit hud falls back to noop with a clear stderr message.

Want to pre-build (e.g. in CI) or refresh the cache?

cept-hud-install            # build if missing
cept-hud-install --force    # rebuild
cept-hud-install --path     # print resolved binary path

The HUD itself is a translucent NSPanel (Swift 5, macOS 13+, top-right of the active screen, click-through, no Dock icon). Source lives in hud/.

Layers

┌─────────────────────────────────────────┐
│ Layer 2 — external steering (OpenRouter)│
└─────────────────────────────────────────┘
                  ▲
┌─────────────────────────────────────────┐
│ Layer 1 — local introspection           │
│  locator → distiller → redactor → packet│
└─────────────────────────────────────────┘
                  │
                  ▼ (events fan out)
┌─────────────────────────────────────────┐
│ Adapters — stdout / file / socket /     │
│ HUD / notify / noop                     │
└─────────────────────────────────────────┘

Layer 1 is independently useful and testable. Layer 2 is the consultation. Adapters are the surface — swap them without touching the pipeline.

About

Proprioception for coding agents — slice recent Claude Code transcript, redact, send to a model gateway, return structured steering guidance.

Topics

Resources

License

Code of conduct

Contributing

Security policy

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors