wheeler / wheeler
CLAUDE.md12 starsChanged 3 months agoMITView on GitHub
Sections: neo4j, graph (backend selection), search, project, paths, workspace, models (per-mode model assignment), knowledge_path, synthesis_path. Precedence for the four neo4j connection fields: NEO4J_* env > OS keychain (wheeler login) > wheeler.yaml > _NEO4J_DEFAULTS. Env stays h
In this repository47 other files it gives its agents.
- .claude/commands/wh/CLAUDE.mdCLAUDE.md
- CLAUDE.mdCLAUDE.md
- docs/CLAUDE.mdCLAUDE.md
- wheeler-briefSkill
- wheeler-service-creatorSkill
- addSkill
- askSkill
- asta-assistantSkill
- asta-litSkill
- asta-reportSkill
- asta-scholarSkill
- astaSkill
- asta-theorizeSkill
- backupSkill
- bumpSkill
- chatSkill
- closeSkill
- compileSkill
- dev-feedbackSkill
- discussSkill
- dreamSkill
- executeSkill
- graph-linkSkill
- graph-reviewSkill
- handoffSkill
- ingestSkill
- initSkill
- lessonSkill
- llmsr-discoverSkill
- llmsr-transferSkill
- noteSkill
- pairSkill
- pauseSkill
- planSkill
- queueSkill
- reconveneSkill
- reportSkill
- restoreSkill
- resumeSkill
- serviceSkill
- skill-creatorSkill
- startSkill
- statusSkill
- triageSkill
- updateSkill
- wheeler-voiceSkill
- writeSkill
The file
We split this CLAUDE.md into the rules it gives an agent
3 rules. About 0 are common, 1 is distinctive, and 2 are very specific to this project.
≈0
Common · estimate
Many files like this have a rule of this kind.
≈1
Distinctive · estimate
This author's own choices. Worth a look.
2
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Very specific: line 53
Prefer the resolved_* properties over bare Path(config.knowledge_path): a relative path is resolved against whatever cwd the process …
- Very specific: line 58
Every add_* mutation writes three things:
- Distinctive: line 72
Never use em dashes. Use colons, commas, periods, parentheses.
≈ “Common” is an estimate: at least 1 in 5 of the 26,980 CLAUDE.md files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
wheeler/ -- Python package
Module Architecture
models.py <- zero internal deps (leaf node, source of truth)
credentials.py <- zero internal deps (OS keychain, lazy `keyring`)
^
config.py <- zero internal deps (YAML loader; lazy credentials.py)
^
knowledge/store.py <- models only
knowledge/render.py <- models only (incl. render_synthesis for Obsidian)
^
graph/* <- models + config
provenance.py <- config + graph.driver (stability, invalidation)
aura.py <- stdlib urllib + lazy config/graph.driver (Aura onboarding)
^
tools/graph_tools/* <- graph + knowledge (lazy imports)
integrations/* <- config + lazy execute_tool (external-service adapters; Asta)
mcp_core.py, mcp_query.py, mcp_mutations.py, mcp_ops.py <- four split MCP servers (the surface)Key Modules
models.py-- Pydantic v2 models for all node types + prefix mappings. Finding has path, artifact_type, source fields.config.py-- YAML config loader (wheeler.yaml), includesknowledge_pathandsynthesis_path. Also the keychain overlay andneo4j_sources()(which layer supplied each Neo4j field)credentials.py-- OS keychain store behindwheeler login(macOS Keychain / libsecret / Credential Manager).keyringis an optional extra (wheeler[login]), imported lazily; every read path degrades to "no stored credentials" and never raisesmachine.py-- stable identity for THIS computer (~/.wheeler/machine.json, a UUID rather than the hostname) plusorigin_props(), the single source of the fourorigin_*fields stamped on every node. Zero internal imports, same rule ascredentials.py; never raises, degrading to a hostname-derived idportability.py-- the${ROOT}/path form.to_portable/resolvehandle NAMED roots (${PROJECT},${DATA},${GDRIVE});relativize/absolutizeare the single-project-root wrappers backup/restore use. Pure: roots are passed in, never looked upaura.py-- Neo4j Aura onboarding: tolerant credentials-file parser, management API (OAuthclient_credentialsonly, no browser flow exists), connect-before-save validation. stdliburllibonlyacts.py-- The one reader of the act corpus (_data/commands/*.md), served over MCP bylist_acts/get_act.modeandorchestrationare DERIVED from each act'sallowed-tools, never declared separatelybuild_plugin.py-- Generates thewhplugin tree for both hosts from the act corpus. Regenerate withpython -m wheeler.build_plugin; never hand-edit the emitted treeprovenance.py-- Stability scoring, invalidation propagation (W3C PROV-DM), detect_and_propagate_stalemcp_core.py,mcp_query.py,mcp_mutations.py,mcp_ops.py-- four split FastMCP servers (the canonical MCP surface). Each registers a role-specific subset of tools. Register new tools in the matching server only.workspace.py-- File discovery + context formatting for system promptsdepscanner.py-- AST-based dependency scanner (imports, data files)request_log.py-- Append-only JSONL request loggingintegrations/-- external-service adapters (Asta first, then LLM-SR equation discovery, which inverts an evolutionary loop into CLI verbs because there is no service to call). The marshal-out ingest modules are the onlyexecute_toolcallers here (lazy, function-local). To add a NEW external service, use thewheeler-service-creatorskill (it scaffolds the adapter with the external-call failsafe baked in and an auditor), do NOT hand-write one. Seeintegrations/asta/CLAUDE.mdandintegrations/llmsr/CLAUDE.md.
Config (wheeler.yaml)
Sections: neo4j, graph (backend selection), search, project,
paths, workspace, models (per-mode model assignment), knowledge_path,
synthesis_path.
Precedence for the four neo4j connection fields:
NEO4J_* env > OS keychain (wheeler login) > wheeler.yaml > _NEO4J_DEFAULTS.
Env stays highest so CI and containers keep working. neo4j_sources() reports
which layer won per field; wheeler login --status prints it.
Project root resolution: WHEELER_PROJECT_ROOT env > explicit project_root in
wheeler.yaml > nearest ancestor holding wheeler.yaml or .wheeler/ > cwd.
Prefer the resolved_* properties over bare Path(config.knowledge_path): a
relative path is resolved against whatever cwd the process happens to have.
Triple-Write
Every add_* mutation writes three things:
- Graph node (Neo4j)
knowledge/{node_id}.json(machine metadata)synthesis/{node_id}.md(human-readable, Obsidian-compatible)
link_nodes re-renders synthesis files for both endpoints.
set_tier updates both JSON and synthesis.
Conventions
from __future__ import annotationsin every module- Stdlib logging with
logging.getLogger(__name__) - Async where graph I/O happens, sync for file I/O
- Lazy imports in
tools/to avoid circular deps withknowledge/ - Never use em dashes. Use colons, commas, periods, parentheses.
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

