Architect agent: Claude-powered thesis generation (backend scaffolding)

- backend/mcp/architect_agent.py: generate_options + revise on Claude (prompt-
  cached thesis context, claude-opus-4-8, Ten31 voice rules). Writes N variant
  drafts to a node's variant group; nothing canonical without human approval.
  Fails gracefully if the API key / SDK is absent.
- server.py endpoints: GET /api/architect/status, GET /api/thesis/{key}/tree,
  GET /api/thesis/nodes/{id}/variants, POST .../generate, POST .../feedback,
  POST /api/thesis/lines, POST /api/thesis/lines/{key}/nodes. architect_tools
  gains get_node_variants.
- Dockerfile installs `anthropic`; docker_entrypoint loads ANTHROPIC_API_KEY from
  /data/secrets/anthropic-api-key (self-disabling until the key is dropped in).

Full HTTP surface verified end-to-end (graceful 502 without a key).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Keysat
2026-06-05 13:25:47 -05:00
parent 91361042e7
commit dd25bbc08d
5 changed files with 281 additions and 1 deletions
+17
View File
@@ -95,6 +95,23 @@ def get_node(node_id, db=None):
return dict(r) if r else {"error": "not_found", "node_id": node_id}
def get_node_variants(node_id, db=None):
"""All competing options for a node (its variant group). The number is fluid:
a node may have one option or many at any moment."""
c = _conn(db)
node = c.execute("SELECT line_id, variant_group, node_type, title FROM thesis_nodes WHERE id=?", (node_id,)).fetchone()
if not node:
c.close()
return {"error": "not_found", "node_id": node_id}
group = node["variant_group"] or node_id
rows = [dict(r) for r in c.execute(
"SELECT id, body, title, status, variant_group, meta FROM thesis_nodes "
"WHERE (variant_group=? OR id=?) AND deleted_at IS NULL ORDER BY created_at", (group, node_id))]
c.close()
return {"node_id": node_id, "variant_group": group, "node_type": node["node_type"],
"title": node["title"], "variants": rows}
def get_node_history(node_id, db=None):
c = _conn(db)
rows = [dict(r) for r in c.execute(