Skip to main content

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

Project description

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

# Include source files for content-shape critique (not just trajectory):
OPENROUTER_API_KEY=sk-or-... cept-cli --goal "audit this readme" \
  --file research-findings/README.md --file checklist.md --mode debug

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

Including source files in the packet

By default, cept's packet describes what the agent did — tool calls, decisions, errors. Trajectory critique catches workflow problems but misses content problems ("this README quotes a statute that's actually from a summary page", "this function ignores its null branch"). Pass file paths to include their content in the packet:

  • MCP: files=["README.md", "src/handler.py"]
  • CLI: repeat --file PATH

Each file is capped at 50 KB; total at 256 KB across all files; max 24 files per call. Truncated files keep the head and append a marker. Binary files (NUL byte detected) are skipped with a note. Paths can be absolute or relative to cwd. Redaction still applies to the file content. When files are present, the system prompt asks the model to cite issues as path:line-range so you can navigate directly to them.

Examples

  • 01 — catching a guardrail violation before it shipped: agent was about to write a persona before deploying the bot. Cept caught that this contradicted the project's own ship-simplest guardrails and surfaced two technical risks (socket-mode on Railway, non-swappable SYSTEM_PROMPT) the agent had missed.

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.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

cept-0.2.0.tar.gz (44.4 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

cept-0.2.0-py3-none-any.whl (37.4 kB view details)

Uploaded Python 3

File details

Details for the file cept-0.2.0.tar.gz.

File metadata

  • Download URL: cept-0.2.0.tar.gz
  • Upload date:
  • Size: 44.4 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for cept-0.2.0.tar.gz
Algorithm Hash digest
SHA256 971077f0868df8ea5f3f1a796919565e118416602ae30acd5caeea615e4b4326
MD5 3ebe1f882ca34b1e20260de3fe22ded5
BLAKE2b-256 7ac879e790e4e700e3ec525149b24b3ee391a46d0d887711993005a59e076593

See more details on using hashes here.

Provenance

The following attestation bundles were made for cept-0.2.0.tar.gz:

Publisher: publish.yml on eidos-agi/cept

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file cept-0.2.0-py3-none-any.whl.

File metadata

  • Download URL: cept-0.2.0-py3-none-any.whl
  • Upload date:
  • Size: 37.4 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for cept-0.2.0-py3-none-any.whl
Algorithm Hash digest
SHA256 f864d010bffeb1b822eebf8f5421e62ff45732df1c7551579b0a44eb7bba403a
MD5 4e4bba3a0882f4eb8015eeb116852306
BLAKE2b-256 adeb275f61f4c07a290b7f93e8c5fd8b9bc273f739f48bcb8e8d50d6289ed259

See more details on using hashes here.

Provenance

The following attestation bundles were made for cept-0.2.0-py3-none-any.whl:

Publisher: publish.yml on eidos-agi/cept

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page