An interactive reasoning environment over the Counter-AI landscape. 11-axis tensor. Record-similarity graph. Mapper topology. Runtime-editable schema. A Claude-backed agent that sees what you see, acts on the canvas, and can author Project records.
Built as a FastAPI backend + React front-end. The previous Streamlit UI is
archived in legacy/.
make install # Python + Node deps
export ANTHROPIC_API_KEY=sk-ant-... # for the agent (page is gated if unset)
make dev # API on :8765, Vite on :5173Open http://localhost:5173. Stop with Ctrl+C (stops both processes).
If :8765 or :5173 are in use on your machine:
make dev API_PORT=9000 WEB_PORT=5180The ApiHealthBanner will tell you explicitly if the Vite proxy hits a
different service (401 / 403 / 404 on /api/axes) — usually a port
collision with another local dev server.
One canvas, four modes. The tensor is a substrate you explore, not a nav tree. Agent is a persistent participant.
┌──────────────────────────────────────────────────────────────────────┐
│ C·AI Explore · Couplings · Gaps · Schema ⌘K ● agent │
├────────┬───────────────────────────────────┬──────────────────────────┤
│ FILTER │ │ DETAIL DRAWER │
│ RAIL │ CANVAS │ │
│ │ (force graph / heatmap / gap │ context-sensitive: │
│ A ● │ matrix / schema editor) │ record, axis, value, │
│ G │ │ coupling, gap, pinned │
│ V ●●● │ │ comparison │
│ … │ │ │
│ Pinned │ │ │
├────────┴───────────────────────────────────┴──────────────────────────┤
│ 🤖 ask the landscape… (streams; action cards; undo; Cmd-/) │
└──────────────────────────────────────────────────────────────────────┘
Modes
| Mode | Canvas |
|---|---|
| Explore | Record-similarity force graph + Mapper-complex toggle. Axis-weight sliders, edge threshold, color by record type / dominant axis. Connection-rule edges overlay in their declared colors. |
| Couplings | X × Y heatmap. Cells are colored by record count. Click a cell → focus records in the drawer. |
| Gaps | Inverted heatmap: empty cells foreground, populated receding. Rank by coupling density, framework silence, or strategic weight. Right column lists top empties. |
| Schema | Axes tab (add overlay axis, add value, hide), Connections tab (author ConnectionRules), YAML preview. Every save flows through the store and re-renders the other modes. |
Agent
Pinned to the bottom. Full read + write tool access:
- Read:
list_records,get_record,search_records,axis_info,value_info,coupling_info,find_gaps,corpus_stats,generate_research_questions,get_design_note,list_design_notes. - Navigate:
set_mode,set_filter,clear_filters,focus_record,pin_record,unpin_record,select_axis_pair,set_graph_weights,set_edge_threshold. - Schema edits:
add_overlay_axis,add_axis_value,hide_axis_value,remove_axis,add_connection_rule,remove_connection_rule. - Authoring:
create_project(writes tocai_tensor/data/projects.yaml). annotate(free-text notes on records / axes / values / cells).
Every agent action renders as an action card in chat with an undo button for reversible ops and an explicit Apply gate for destructive ones. The agent sees current mode / filters / focus / pinned as a system-reminder block each turn, so it reasons about context without needing to always tool-call for it.
Streaming model: SSE at /api/agent/turn. Text tokens stream live;
tool_use_start renders a collapsible block; tool_result fills in the
output; state_mutation events apply to the Zustand store.
| Chord | Action |
|---|---|
⌘K |
Command palette (fuzzy search: records, axes, actions) |
⌘/ |
Focus agent input |
⌘E |
Toggle detail drawer |
⌘1 … ⌘4 |
Switch modes |
Esc |
Clear focus / close agent |
.
├── api/ # FastAPI backend
│ ├── main.py # app factory + CORS
│ ├── deps.py # filter_records, record_by_id
│ ├── serializers.py # JSON shapes
│ ├── agent_tools.py # read + write tool registry
│ └── routers/ # records, axes, graph, gaps, stats,
│ # schema, annotations, projects, agent
├── cai_tensor/
│ ├── schema.py # 11-axis pydantic enum schema (authority)
│ ├── schema_runtime.py # YAML overlay + effective_axes
│ ├── corpus/
│ │ ├── incidents.py # 20 incidents as Python
│ │ ├── frameworks.py # 15 framework projections
│ │ └── projects.py # YAML-backed authored Projects
│ ├── data/ # corpus.json (generated), schema.yaml, projects.yaml, annotations.yaml
│ ├── semantics/ # axis / value / coupling / design notes
│ ├── graph/ # similarity + Mapper + connection edges
│ ├── agent/ # tools, context, prompts (Opus 4.7 + adaptive thinking)
│ ├── annotations.py # free-text notes
│ └── questions.py # research-question templates
├── frontend/ # Vite + React 19 + TS + Tailwind v4
│ ├── src/
│ │ ├── App.tsx # three-region layout + keyboard
│ │ ├── store.ts # Zustand store (single source of truth)
│ │ ├── lib/api.ts # typed API client
│ │ ├── lib/agent.ts # SSE parser / streaming generator
│ │ ├── components/ # TopBar, FilterRail, Drawer, CommandPalette
│ │ ├── components/agent/ # AgentDock, MessageView, stateMutations
│ │ ├── components/detail/ # RecordDetail, AxisDetail, ValueDetail, CouplingDetail, GapDetail
│ │ └── views/ # ExploreCanvas, CouplingsCanvas, GapsCanvas, SchemaCanvas
│ ├── index.html
│ ├── vite.config.ts # proxy /api → :8000
│ └── package.json
├── tests/ # pytest suite (91 tests)
├── legacy/ # archived Streamlit build
├── docs/ # design-react.md, walkthrough.md
├── tensor_v2.md # axis reconciliation (authority)
├── Makefile # make install / dev / api / web / build / test
└── requirements.txt
make test # python pytest — 91 tests
cd frontend && pnpm tsc --noEmit -p tsconfig.app.json # strict TypeScript
cd frontend && pnpm build # production bundleThe python suite covers schema, corpus, semantic coverage (every axis has a note, every enum value has a note, every lane-question pair has a coupling note), graph construction, Mapper clustering, schema overlay round-trip, agent action tool dispatch, annotations CRUD, project CRUD, and every FastAPI endpoint end-to-end.
- New incident / framework → edit
cai_tensor/corpus/incidents.pyorframeworks.py(Python). - New value on existing axis → use the Schema mode UI, or POST
/api/schema/axes/{sym}/values, or have the agent calladd_axis_value. - New axis → Schema mode → Axes tab → "Add overlay axis". Or agent
add_overlay_axis. Existing corpus records are empty on the new axis until populated. - Connection rule → Schema mode → Connections tab. Renders as colored edges in Explore.
- Project record → ask the agent to draft one from a gap cell, or POST
/api/projectsdirectly. - Annotation → agent
annotatetool, or POST/api/annotations.
All live-edited content (overlay, projects, annotations) lands in YAML files
under cai_tensor/data/ that are safe to git diff.
| Var | Purpose |
|---|---|
ANTHROPIC_API_KEY |
Required for the agent. Everything else works without it. |
CAI_ALLOWED_ORIGINS |
Extra CORS origins (comma-separated). Defaults cover Vite dev. |
docs/design-react.md— the canvas-first design spec (layout, aesthetic, agent action model, tech stack, stage plan).docs/walkthrough.md— 10-minute narrative for new analysts.tensor_v2.md— axis reconciliation (the contract).tensor_v2_stress_test.md— validation findings.corpus_build_notes.md— corpus observations.visuals_spec.md— (legacy Streamlit spec, superseded by the React build).CLAUDE.md— guidance for Claude Code working in this repo.legacy/— archived Streamlit implementation.