feat: Claude Code context injection (UserPromptSubmit hook)
Closes the asymmetry the user surfaced: before this, Claude Code captured every turn (Stop hook) but retrieval only happened when Claude chose to call atocore_context (opt-in MCP tool). OpenClaw had both sides covered after 7I; Claude Code did not. Now symmetric. Every Claude Code prompt is auto-sent to /context/build and the returned pack is prepended via hookSpecificOutput.additionalContext — same as what OpenClaw's before_agent_start hook now does. - deploy/hooks/inject_context.py — UserPromptSubmit hook. Fail-open (always exit 0). Skips short/XML prompts. 5s timeout. Project inference mirrors capture_stop.py cwd→slug table. Kill switch: ATOCORE_CONTEXT_DISABLED=1. - ~/.claude/settings.json registered the hook (local config, not committed; copy-paste snippet in docs/capture-surfaces.md). - Removed /wiki/capture from topnav. Endpoint still exists but the page is now labeled "fallback only" with a warning banner. The sanctioned surfaces are Claude Code + OpenClaw; manual paste is explicitly not the design. - docs/capture-surfaces.md — scope statement: two surfaces, nothing else. Anthropic API polling explicitly prohibited. Tests: +8 for inject_context.py (exit 0 on all failure modes, kill switch, short prompt filter, XML filter, bad stdin, mock-server success shape, project inference from cwd). Updated 2 wiki tests for the topnav change. 450 → 459. Verified live with real AtoCore: injected 2979 chars of atocore project context on a cwd-matched prompt. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -29,7 +29,6 @@ from atocore.projects.registry import load_project_registry
|
||||
_TOP_NAV_LINKS = [
|
||||
("🏠 Home", "/wiki"),
|
||||
("📡 Activity", "/wiki/activity"),
|
||||
("📥 Capture", "/wiki/capture"),
|
||||
("🔀 Triage", "/admin/triage"),
|
||||
("📊 Dashboard", "/admin/dashboard"),
|
||||
]
|
||||
@@ -337,16 +336,27 @@ def render_search(query: str) -> str:
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------
|
||||
# Phase 7I follow-up — /wiki/capture: paste mobile/desktop chats
|
||||
# /wiki/capture — DEPRECATED emergency paste-in form.
|
||||
# Kept as an endpoint because POST /interactions is public anyway, but
|
||||
# REMOVED from the topnav so it's not promoted as the capture path.
|
||||
# The sanctioned surfaces are Claude Code (Stop + UserPromptSubmit
|
||||
# hooks) and OpenClaw (capture plugin with 7I context injection).
|
||||
# This form is explicitly a last-resort for when someone has to feed
|
||||
# in an external log and can't get the normal hooks to reach it.
|
||||
# ---------------------------------------------------------------------
|
||||
|
||||
|
||||
def render_capture() -> str:
|
||||
lines = ['<h1>📥 Capture a conversation</h1>']
|
||||
lines = ['<h1>📥 Manual capture (fallback only)</h1>']
|
||||
lines.append(
|
||||
'<p>Paste a chat from Claude Desktop, Claude.ai (web or mobile), '
|
||||
'or any other LLM. It goes through the same pipeline as auto-captured '
|
||||
'interactions: extraction → 3-tier triage → active memory if it carries signal.</p>'
|
||||
'<div class="triage-warning"><strong>This is not the capture path.</strong> '
|
||||
'The sanctioned capture surfaces are Claude Code (Stop hook auto-captures every turn) '
|
||||
'and OpenClaw (plugin auto-captures + injects AtoCore context on every agent turn). '
|
||||
'This form exists only as a last resort for external logs you can\'t get into the normal pipeline.</div>'
|
||||
)
|
||||
lines.append(
|
||||
'<p>If you\'re reaching for this page because you had a chat somewhere AtoCore didn\'t see, '
|
||||
'fix the capture surface instead — don\'t paste. The deliberate scope is Claude Code + OpenClaw.</p>'
|
||||
)
|
||||
lines.append('<p class="meta">Your prompt + the assistant\'s response. Project is optional — '
|
||||
'the extractor infers it from content.</p>')
|
||||
|
||||
Reference in New Issue
Block a user