axagent experiencelivev0.32.0
what's under the hood

What ax knows about your agent.

A tour of the data ax keeps on your laptop - the transcripts it indexes, the graph it builds, the stages it derives, the interventions it proposes, and the hooks it watches in real time.

369,132user + assistant turns
4,773sessions ingested
5.9msmedian FTS query
8 stagesderived per ingest

One developer's local graph, as of June 2026. Turn count is role-filtered to user + assistant exchanges - the real signal, not raw provider events.

01 / Sources

Everything your agent already wrote down.

Five coding harnesses, plus git and your installed skills. ax reads all of them.

Claude transcripts~/.claude/projects/*.jsonl
Codex sessions~/.codex/sessions/*.jsonl
Pi sessions~/.pi/agent/sessions/*.jsonl
OpenCode + Cursorlocal SQLite stores
Git historycommits · file changes
Hook firespre-tool · post-tool · stop
Installed skills~/.claude/skills/ · ~/.agents/skills/ · ~/.claude/plugins/cache/
graphSurrealDB · local

A LaunchAgent (com.necmttn.ax-watch) tails your Claude and Codex transcript directories and runs ax ingest --since=1 in the background within seconds of a new turn. A weekly self-improve cron for deep-scan backfill is on the roadmap (wire-up pending). Nothing is uploaded, queued, or phoned home - every read stays on the same filesystem your agent already writes to.

liveLaunchAgent tails new turns, ingests in ~2s
roadmapweekly cron deep-scan backfill for missed sessions + drift (wire-up pending)
02 / The graph

A typed graph of who did what, where.

Transcripts become nodes and edges. Sessions own turns. Turns invoke tools. Tools touch files. Files end up in commits.

// schema sketch - SurrealDB v3, ns=ax, db=main session ────▶ turn ──invoked──▶ skill │ │ │ ├──(owns)───▶ tool_call │ └──edited───▶ file │ └──produced──▶ commit ──touched──▶ file // relations are first-class - every edge is queryable
Nodes - 7 of ~14
sessionone agent conversation, start → end
compactioncontext ran out and got summarized
turna single user-assistant exchange
tool_callRead, Edit, Bash, MCP - one invocation
skillan installed Claude/Agents skill
filea path the agent read or wrote
commitgit commit attributed to a session
Relations - 4
invokedturn → skill (Skill tool call)
editedturn → file (Edit/Write)
touchedcommit → file
producedsession → commit
03 / Derive stages

Raw events become findings.

Once the graph is built, ax runs a chain of small derive stages. Each one writes back into the same database, so every later query can ask the typed question instead of the raw one.

closurecommit
Classifies each commit as feature-only or feature-then-fix.
writes commit_classification
skill_candidatepattern
Finds fix-chain patterns worth packaging as a skill.
writes skill_candidate
session_healthsession
Tokens, cache hit-rate, and context pressure per session.
writes session.health
friction_eventsignal
Surfaces what failed, where, and how often.
writes friction_event
command_outcometool
Tags tool calls: success · expected-feedback · guardrail · failure.
writes tool_call.outcome
workflow_epochwindow
Splits your history into eras by toolset and workflow shape.
writes workflow_epoch
harness_doctorinstall
Audits installed skills, hooks, plists, and settings.json for drift, conflicts, dead weight.
live audit - no table; surfaced by ax doctor
classifiersharness
Pluggable graph classifiers that read derived rows and emit higher-order labels.
writes classifier_result
04 / Interventions

Proposals, lifecycle, and safety gates.

Patterns that recur in your graph turn into Intervention proposals. Each one moves through a tracked lifecycle, and any change to your harness ships with a written rollback contract.

Six forms
skilla new SKILL.md packaging a repeated pattern
guidancea line of instruction added to a grounded file
subagenta routed sub-agent under ~/.claude/agents/
hooka typed pre/post-tool gate in ~/.ax/hooks/, fanned into both harnesses
automationa plist or cron entry that runs on a schedule
harness_checka doctor assertion that proves the change still holds
Intervention safety contract
recovery_pathwritten rollback steps. Required on every hook + automation.
smoke_test_commandone shell command that proves the agent still works after.
disable_commandkill switch you can paste from memory in a panic.
failure_modefail_open (let through if hook errors) or fail_closed.
Lifecycle - eight states, checkpointed against future sessions
openacceptedtask_emittedmarker_landed+3 sessions+10 sessions+30 sessionslocked_verdict
Manual-safe by commitment. ax never edits settings.json, hooks, LaunchAgents, cron, or shell scripts directly. An accepted intervention emits a task brief at .ax/tasks/<id>.md with the safety contract on top. You - or your agent - apply it. ax improve lint reads the marker you left behind to reconcile the proposal back to accepted state.
.ax/tasks/hook_chk_skip_test_runner.mdmd
---
form: hook
experiment: experiment:chk_skip_test_runner
recovery_path: Remove the matching block from ~/.claude/settings.json,
                  restart Claude Code, run smoke test.
smoke_test_command: bun test src/ingest/turns.test.ts
disable_command: jq 'del(.hooks.PreToolUse[] | select(.matcher=="Bash"))' \
                  ~/.claude/settings.json > /tmp/s.json && mv /tmp/s.json ~/.claude/settings.json
failure_mode: fail_open
---

# Hook: block `bun test` without the wrapper

Add to ~/.claude/settings.json hooks.PreToolUse:

{
  "matcher": "Bash",
  "hooks": [{
    "type": "command",
    "command": "echo 'ax:chk_skip_test_runner' && ax-hook check-test-runner"
  }]
}

The echo line is the marker ax improve lint looks for.
05 / Hooks

Write a hook once, run it in both.

Claude Code and Codex each have their own hook config and zero shared tooling. @ax/hooks-sdk lets you author a guardrail once in typed Effect TypeScript, backtest it against your own tool history, and install the same file into both harnesses.

~/.ax/hooks/enforce-worktree.tsts
import { defineHook, Verdict, GitEnv } from "@ax/hooks-sdk";
import { Effect } from "effect";

export default defineHook({
  name:    "enforce-worktree",
  events:  ["PreToolUse"],
  matcher: { tools: ["Bash"] },
  run: (event) =>
    Effect.gen(function* () {
      const git = yield* GitEnv;
      // block branch switches on the primary tree
      if (switchesBranch(event) &&
          (yield* git.isPrimaryTree(event.cwd)))
        return Verdict.block("use a worktree instead");
      return Verdict.allow;
    }),
});
One file, both harnesses
ax hooks init scaffolds ~/.ax/hooks. ax hooks install <file> --providers=claude,codex fans the same hook into both provider configs, idempotently. Fire path is bun <file>.ts - about 70ms, no daemon.
Backtest before you trust it
ax hooks backtest ./my-hook.ts --days=14 replays your real tool_call history through the hook in-process: would-block count and rate, per-project breakdown, sample blocked commands. First real run: 10,992 calls replayed, 0.8% would-block.
Fail open, always
run returns a verdict - allow, block with a reason, warn, or inject context. A hook that throws fails open: the tool call proceeds, and a buggy guard never wedges your agent.
06 / Surfaces

One CLI, every query.

Everything ax knows is reachable from ax. The dashboard, TUI, and MCP server are the same queries with different paint.

ax recall <q>BM25 full-text search across every user + assistant turn. Median 5.9ms.
ax contextBuilds a just-in-time context pack from the graph for the next session.
ax hooks init / install / backtest / casesScaffold ~/.ax/hooks, fan a hook into Claude Code + Codex, replay history through it, score known cases.
ax doctorHarness health check - drift, conflicts, dead weight across skills + hooks + plists.
ax dispatches --candidates · ax routing tune / compile / showSee where subagent spend goes, then route mechanical dispatches to cheaper models. The route-dispatch hook is the deterministic backstop.
ax cost models / sessions / splitPer-model and origin (main vs subagent) cost rollups with estimated USD and share-of-total.
ax quota --statusline / --swiftbarLive Claude plan usage (5h / 7d windows) in the CLI, statusline, or menubar. Cached, no DB.
ax profile show / publishRender your local ax profile, or publish it to a public gist - opt-in, consent-gated, registered into the community leaderboard.
ax improve list / show / accept / reject / lint / verdict / checkpointWalk the intervention queue. Accept emits a task brief; lint reconciles the marker.
ax serveLocal web dashboard at 127.0.0.1:1738 with the same data the TUI sees.
ax mcpStdio MCP server - exposes ax's read-only queries as 17 tools so Claude Code or Codex can query the graph in-context.
ax tuiInteractive terminal dashboard. Sessions, interventions, harness in one pane.
ax ingest --since=NWhat the LaunchAgent calls on every new transcript. Idempotent; safe to rerun.
07 / Local-first

One process, one database, one laptop.

ax is a single binary that runs as a LaunchAgent, talks only to localhost, and stores everything in a SurrealDB instance you own.

database127.0.0.1:8521SurrealDB v3, schemafull. Namespace ax, db main.
dashboard127.0.0.1:1738Web UI for the graph, findings, and intervention queue. No auth - it's your loopback.
daemonLaunchAgentmacOS + Linux, installed by ax install. Survives reboots.
licenseAGPL-3.0 · single binaryBuilt with Bun. No cloud account, no telemetry egress. ax uninstall removes it. Commercial license available.

“Your transcripts are already on your laptop. ax just reads them where they sit.”