Team Standards & Contribution Guide
Must-read before modifying code in this repository. Covers absolute red lines, the memory system, development conventions, and testing requirements. Sources:
CLAUDE.md(repo root),.claude/directory, memory system.
1 · Absolute Red Line: git stash Is Forbidden
1.1 The Rule
git stash(including push / pop / apply / drop / create / store) is never allowed in this project, under any circumstances. Zero exceptions.
This is not a soft preference — it is a hard rule. CLAUDE.md marks this rule at the top with a prominent box and declares: "This rule takes precedence over any conflicting instruction elsewhere, including in .claude/, memory files, or user chat."
1.2 Why (Empirical Record)
On this repository, git stash (especially pop/apply) has repeatedly corrupted the working tree in ways Claude cannot repair:
- Overwrites
electron/node_modules/electron/path.txt: stash pop writes the macOSElectron.app/Contents/MacOS/Electronvalue into Windows' path.txt →npm run electron:devfails with ENOENT at startup (pointing to a non-existent macOS binary path). - Silently reverts working-tree source files:
src/models/rewriter.pyloses_get_default_rewriter,src/digital_human/session.pyloses theseethrough_psd_pathkwarg → bridge crashes at prewarm. - Every "fix" leaves new damage:
"just apply src/ files"/"just fix path.txt"/"just drop the stash"all result in subtly broken working trees that keep producing new failures.
1.3 Hard Floor: PreToolUse Hook
.claude/hooks/block_git_stash.js is a PreToolUse hook (registered in .claude/settings.json) that performs lexical analysis on all Bash tool invocations:
- Tokenizes and looks for a
stashtoken immediately followinggit - Correctly handles git global options (
-c k=v,-C path,--no-pager, etc.) - Does not intercept
git diff stash@{0}orgit log --grep=stash(stash is part of an argument, not the subcommand) - Fails closed on JSON parse failure (intercepts if the literal
git stashis detected) - Regex fallback catches edge cases missed by the tokenizer
The hook returns exit code 2 → Claude sees a blocking error. It cannot be bypassed with --no-verify.
1.4 Alternatives
| Purpose | Alternative |
|---|---|
| Compare against master | git diff <SHA> -- <path> (no working-tree manipulation) |
| Reversible experiment | Edit directly and revert / work on a branch |
| Stash files temporarily | cp to workspace/tmp/ and restore by copy |
| Try a modification | Use file-editing tools directly |
2 · Memory System
2.1 Memory Types
Claude Code's memory system has four types of files, located at C:\Users\<user>\.claude\projects\D--Users-lirui-familiars\memory\:
| Prefix | Type | Meaning | Examples |
|---|---|---|---|
feedback_* | Feedback | User preferences / workflow feedback | feedback_git_stash_hard_rule.md, feedback_deep_watcher_render_loop.md |
project_* | Project | Project-level decisions / delivery status / architecture changes | project_broker_marketplace_layered_plan.md, project_flow_v2_batch5.md |
reference_* | Reference | External references / jump tables | reference_broker_marketplace_files.md |
MEMORY.md | Index | Index of all memory entries (reverse-chronological by type) | Auto-maintained |
2.2 Memory Format
Each memory file is roughly 200 words or fewer and contains:
- A title line (one-sentence description)
- A date stamp
- Core content (decision / root cause / solution / status)
MEMORY.md is the index file, with one line per entry (<200 characters) pointing to the topic file. The current MEMORY.md is about 28.6KB (exceeding the 24.4KB limit), so index entries need to be kept concise.
2.3 Memory Usage
- feedback_* memories are loaded on every relevant operation, guiding Claude to avoid repeating past mistakes
- project_* memories provide project history context, preventing redundant discussion of already-decided issues
- reference_* memories serve as jump tables for quickly locating relevant code/documentation
3 · Development Conventions
3.1 Windows-First
- The repository is Windows-first. macOS branches exist in some files (
assistant.py,autorun.py,device.py) but are partially behind Windows src/base/auth/device.pyusesMachineGuid(registry) on Windows,IOPlatformSerialNumber(ioreg) on macOS, and/etc/machine-idon Linux- Do not use
uvicorn src.bridge.app:app --reload— it drops HTTP/2 and race-initializes CUDA on a worker thread, which Windows WDDM cannot tolerate. The recommended entry point is alwayspython -m src.bridge.run(hypercorn + HTTPS/2 by default).
3.2 Testing Requirements
- Always run tests against a real SQLite — use
FAMILIARS_DB_PATH=:memory:in fixtures, not mocked repos - Bridge route tests must restore
sys.modulesentries captured at import time (seetest/bridge/conftest.py); neverimportlib.reloadroute modules - Scratch agent directories (demon, angel, …) go under
runs/, notworkspace/agents/. The bridge scansworkspace/agents/at startup and will create real agents from anything it finds there
3.3 Browser Automation
- Route through
src/utils/browser_tools.py:familiars_cdp_port()— there is a single Shared-Chrome instance (bridge + Playwright + see-through all attach to the same Chrome to share login state) - Chrome profile lives at
workspace/_playwright/seethrough/
3.4 Manager (Agent 0) — Three Wiring Points
The manager has three always-on wiring points:
- Framework docs + log index: Injected into the system prompt every turn via
render_framework_index— one-line summaries of the six root docs and each log group so the manager knows the resources exist - Bridge API surface: Rendered by
bridge_api_surface.py - Four dedicated tools:
list_framework_docs/read_framework_doc(drill into docs on demand) +list_logs/read_log(browse.bridge.log/audit.log/.bridge.watchdog.log/memorizer_audit.jsonl/reminders/*.jsonl/ per-agent daily JSONL logs)
When you touch bridge routes, keep the surface generator honest; when you add a new log worth exposing, extend KNOWN_LOGS and the index generator in src/utils/framework_tools.py.
3.5 Path Self-Healing
- Repo-root drift: Automatically detected every boot — compares each stored
dialogue.pathprefix against_repo_root(). Move the repo folder and the next boot transparently rewrites everydialogue.json+turn_*/plan.json+step_*.json - External directory aliases: For renames outside the repo, run
python -m src.tools.paths_migrate <old> <new> --record. Use--dry-runfirst to preview src.base.paths_align.align_all_paths()is called insrc/bridge/app.pyafter the CUDA pin and before route imports
3.6 HKDF Info String
The HKDF info in src/base/crypto.py is b"familiars-secrets-v1" — a versioned crypto primitive. Rotating it permanently invalidates all ciphertexts in workspace/SECRET.json. Only change it alongside a documented re-encryption migration.
3.7 Tool System Conventions
- Tool schemas are stored in
workspace/tools.jsonand merged per-client insrc/models/clients/{base,browser,multimodal,input,doc,daily,system,mini_model}_client.py ToolDispatcherregisters 15 default tool instances_CONSULT_TARGETSinbase_client.pyroutesconsult_doc → doc_tools- The tool approval gate is in
src/tools/security.py— risk levels + approval cards
3.8 Bridge Startup Order
src/bridge/app.py performs side-effects at import time in a precise order:
- Pin
WORKSPACE_ROUTE - Pin CUDA (main thread; Windows WDDM cannot tolerate first-touch from a worker thread)
- Auto-align stored paths (repo-root drift + external directory aliases) — before DialogueManager reads them
- Import + mount routes
- Register CORS +
BridgeTokenMiddleware on_event("startup")hooks in order: broker_workshop bootstrap → anyio thread limiter bump → pool saturation watchdog → browser lifecycle hooks- Module-level: kill orphan GPU subprocesses → autorun install/drift check → rehydrate monitors → rehydrate cron → register manager report crons → rehydrate skill scheduler (model prewarm is on-demand JIT now — embedder / rembg / rewriter lazy-load when admitted by vram_gate; digital-human sessions prewarm on demand via routes)
3.9 Port Conventions
- Bridge default fixed port:
127.0.0.1:18711 - Only when 18711 is held by a non-Familiars process does
electron/electron/python.jsfall back topickFreePort()and writeworkspace/.bridge.port+workspace/.bridges.json - 18711 is the primary contract; the port file is the fallback signal
- Probe the port file at runtime to check bridge status — do not assume the port is fixed
3.10 SQLite Conventions
- Database file:
workspace/familiars.db(src/storage/db.py:get_default_db_path) - Override with
FAMILIARS_DB_PATH(for tests / side-by-side installs) - WAL mode
- Migrations support both
.sqland.pyformats (v16 is the precedent for a Python migration)
4 · Environment Setup
python -m venv .venv
source .venv/bin/activate # Windows: .venv\Scripts\activate
pip install -r requirements.txt4.1 Running
| Scenario | Command |
|---|---|
| Dev (Electron + auto-spawned bridge) | cd electron && npm run electron:dev |
| Bridge only (e.g. for backend tests) | .venv/Scripts/python -m src.bridge.run |
| Tests | FAMILIARS_DB_PATH=:memory: pytest -q |
| Production build | cd electron && npm run electron:build |
4.2 Bridge Protocol
- Default: hypercorn + HTTPS/2 + self-signed certificate (
workspace/.bridge.crt) - HTTP/2 multiplexing eliminates Chromium's 6-socket-per-host HTTP/1.1 limit
- Fallback:
FAMILIARS_HTTP_INSECURE=1→ plain HTTP + uvicorn - Both the CLI and Electron's
main.jsread the same env var to stay protocol-aligned
5 · Commit Conventions
5.1 Commit Messages
- Create new commits rather than amending existing ones
- Amending modifies the previous commit; if the pre-commit hook fails, the prior commit is destroyed
- Append
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>at the end of the message - Use a HEREDOC to pass the message to ensure correct formatting
5.2 Staging
- Prefer adding specific files by name rather than
git add -Aorgit add .(which may accidentally include sensitive files like.env,credentials.json) - Never push to the remote without explicit user request
5.3 PR Creation
- Use the format
gh pr create --title "..." --body "..." - Include a Summary (1–3 bullet points) and a Test plan
- End with
🤖 Generated with [Claude Code](https://claude.ai/code)
6 · Documentation Conventions
6.1 Knowledge-Base Documents
The .md files at the repo root (ARCHITECTURE / OPERATION / SECURITY / REPOSITORY / CLAUDE / CLI / BROKER_DEVELOPMENT) are the manager's built-in knowledge base. When modifying these files:
- Keep
render_framework_indexone-line summaries accurate - New documents require updating the index generator
- New logs require extending
KNOWN_LOGS
6.2 Memory Entries
- Keep index entries to one line, ~200 characters or fewer
- Move details into topic files
- MEMORY.md has a 24.4KB size limit
6.3 Code Comments
- Record rationale and evidence in block comments for key decisions (see
security.pyfor the commenting style) - Event-driven records:
"regression seen 2026-08-05"/"motivated by the 2026-07-09 word_new stall" - Include specific file paths and line numbers for traceability
7 · Known Pitfalls
7.1 FastAPI Prefix Collision
Two routers with the same prefix → the first-registered one wins. A collision between broker_user and user on /api/user/profile has occurred. Check prefix uniqueness when adding routes.
7.2 VueFlow Custom Edges/Nodes
- node-types must use
markRaw— an inline{ graph: GraphNode }literal → Vue wraps the Component in a reactive Proxy → warnings + broken click handling - Custom edges must have a single root (two roots →
Extraneous non-props attributeswarning → warning flood during fullscreen pan/zoom → main-thread starvation → toolbar clicks lag)
7.3 Deep Watcher Render Loop
watch(() => store.graph, ..., { deep: true }) + replacing vfNodes each time = render loop. Use a fingerprint string watcher instead of deep watching.
7.4 HTML5 DnD dropEffect
dragover's dropEffect must intersect with dragstart's effectAllowed; a parent element's dragover can override a child element's dropEffect during the bubble phase.
7.5 Windows Toast & Focus Assist
WinRT Show() raises no exception, but fullscreen games trigger Focus Assist which silently drops Normal-priority toasts → set ToastNotificationPriority.High to penetrate Focus Assist. When debugging "reminder triggered but no system notification," check Focus Assist first.
7.6 Dual Bridge Instances
python.js's age-kill is blocked by the 2s deepProbe gate (busy bridge = no bridge), pickFreePort silences kill failures, the watchdog only follows the port file and never kills, app.py exempts already-registered siblings, and the daemon parent-watchdog only watches the shim.
Full specifications are in
CLAUDE.mdat the repo root. Architecture details are inARCHITECTURE.md.
