@nexus-cortex/server 4.26.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.cortex/agents/AGENT_PROFILE_GUIDE.md +307 -0
- package/.cortex/agents/README.md +268 -0
- package/.cortex/agents/a-frontend-landing-page-designer.md +41 -0
- package/.cortex/agents/autoresearch-agent.md +49 -0
- package/.cortex/agents/code-reviewer.md +63 -0
- package/.cortex/agents/context-research.md +26 -0
- package/.cortex/agents/doc-writer.md +92 -0
- package/.cortex/agents/explore.md +63 -0
- package/.cortex/agents/new-model-api-integrator-analyst.md +41 -0
- package/.cortex/agents/plan.md +109 -0
- package/.cortex/agents/pr-architecture-reviewer.md +77 -0
- package/.cortex/agents/pr-code-quality.md +78 -0
- package/.cortex/agents/pr-implementer.md +50 -0
- package/.cortex/agents/pr-security-auditor.md +62 -0
- package/.cortex/agents/pr-test-writer.md +67 -0
- package/.cortex/agents/refactor.md +118 -0
- package/.cortex/agents/test-writer.md +72 -0
- package/.cortex/agents/web-researcher.md +72 -0
- package/.cortex/bench/tasks/sample-tasks.json +20 -0
- package/.cortex/commands/compare.md +14 -0
- package/.cortex/commands/deps.md +16 -0
- package/.cortex/commands/diff.md +14 -0
- package/.cortex/commands/explain.md +16 -0
- package/.cortex/commands/find-bug.md +13 -0
- package/.cortex/commands/profile.md +15 -0
- package/.cortex/commands/review.md +18 -0
- package/.cortex/commands/search.md +16 -0
- package/.cortex/commands/test.md +15 -0
- package/.cortex/permissions.dev.json +20 -0
- package/.cortex/permissions.example.json +71 -0
- package/.cortex/permissions.prod.json +63 -0
- package/.cortex/permissions.test.json +19 -0
- package/.cortex/skills/autoresearch/SKILL.md +77 -0
- package/.cortex/skills/autoresearch/personas/README.md +45 -0
- package/.cortex/skills/autoresearch/personas/aggressive-refactor.md +25 -0
- package/.cortex/skills/autoresearch/personas/creative.md +29 -0
- package/.cortex/skills/autoresearch/personas/perf-hunter.md +27 -0
- package/.cortex/skills/autoresearch/personas/precise.md +23 -0
- package/.cortex/skills/autoresearch/personas/root-cause.md +26 -0
- package/.cortex/skills/autoresearch/personas/security-auditor.md +29 -0
- package/.cortex/skills/autoresearch/personas/skeptic-reviewer.md +31 -0
- package/.cortex/skills/autoresearch/personas/test-first.md +25 -0
- package/.cortex/skills/best-of-n/SKILL.md +76 -0
- package/.cortex/skills/cortex/SKILL.md +834 -0
- package/.cortex/skills/cortex-bench/SKILL.md +354 -0
- package/.cortex/skills/docx/SKILL.md +83 -0
- package/.cortex/skills/pdf-documents/SKILL.md +297 -0
- package/.cortex/skills/pdf-documents/sections/01-image-acquisition.md +132 -0
- package/.cortex/skills/pdf-documents/sections/02-ai-image-generation.md +274 -0
- package/.cortex/skills/pdf-documents/sections/03-paper-sizes.md +89 -0
- package/.cortex/skills/pdf-documents/sections/04-design-system.md +549 -0
- package/.cortex/skills/pdf-documents/sections/05-css-print-rules.md +135 -0
- package/.cortex/skills/pdf-documents/sections/06-svg-charts.md +100 -0
- package/.cortex/skills/pdf-documents/sections/07-templates.md +224 -0
- package/.cortex/skills/pdf-documents/sections/08-scaled-output.md +164 -0
- package/.cortex/skills/pdf-documents/sections/09-preview-qa.md +66 -0
- package/.cortex/skills/pdf-documents/sections/10-reading-pdfs.md +499 -0
- package/.cortex/skills/pdf-documents/sections/11-form-filling.md +241 -0
- package/.cortex/skills/pptx/SKILL.md +90 -0
- package/.cortex/skills/resume-analyst/SKILL.md +373 -0
- package/.cortex/skills/verify-work/SKILL.md +74 -0
- package/.cortex/skills/xlsx/SKILL.md +101 -0
- package/.cortex/system-messages/messages/WORK_QUALITY.md +159 -0
- package/.cortex/system-messages/registry.json +18 -0
- package/LICENSE +202 -0
- package/NOTICE +2 -0
- package/README.md +13 -0
- package/bin/cortex-daemon.js +47 -0
- package/bin/cortex-server.js +15 -0
- package/dist/index.d.ts +30 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +513 -0
- package/dist/index.js.map +1 -0
- package/dist/middleware/cors.d.ts +10 -0
- package/dist/middleware/cors.d.ts.map +1 -0
- package/dist/middleware/cors.js +11 -0
- package/dist/middleware/cors.js.map +1 -0
- package/dist/middleware/errorHandler.d.ts +10 -0
- package/dist/middleware/errorHandler.d.ts.map +1 -0
- package/dist/middleware/errorHandler.js +15 -0
- package/dist/middleware/errorHandler.js.map +1 -0
- package/dist/routes/approval.d.ts +2 -0
- package/dist/routes/approval.d.ts.map +1 -0
- package/dist/routes/approval.js +96 -0
- package/dist/routes/approval.js.map +1 -0
- package/dist/routes/config.d.ts +2 -0
- package/dist/routes/config.d.ts.map +1 -0
- package/dist/routes/config.js +70 -0
- package/dist/routes/config.js.map +1 -0
- package/dist/routes/health.d.ts +2 -0
- package/dist/routes/health.d.ts.map +1 -0
- package/dist/routes/health.js +1031 -0
- package/dist/routes/health.js.map +1 -0
- package/dist/routes/mcp.d.ts +2 -0
- package/dist/routes/mcp.d.ts.map +1 -0
- package/dist/routes/mcp.js +251 -0
- package/dist/routes/mcp.js.map +1 -0
- package/dist/routes/messages.d.ts +5 -0
- package/dist/routes/messages.d.ts.map +1 -0
- package/dist/routes/messages.js +136 -0
- package/dist/routes/messages.js.map +1 -0
- package/dist/routes/middleware.d.ts +2 -0
- package/dist/routes/middleware.d.ts.map +1 -0
- package/dist/routes/middleware.js +146 -0
- package/dist/routes/middleware.js.map +1 -0
- package/dist/routes/models.d.ts +2 -0
- package/dist/routes/models.d.ts.map +1 -0
- package/dist/routes/models.js +29 -0
- package/dist/routes/models.js.map +1 -0
- package/dist/routes/permissions.d.ts +2 -0
- package/dist/routes/permissions.d.ts.map +1 -0
- package/dist/routes/permissions.js +253 -0
- package/dist/routes/permissions.js.map +1 -0
- package/dist/routes/pr.d.ts +2 -0
- package/dist/routes/pr.d.ts.map +1 -0
- package/dist/routes/pr.js +222 -0
- package/dist/routes/pr.js.map +1 -0
- package/dist/routes/sessions.d.ts +2 -0
- package/dist/routes/sessions.d.ts.map +1 -0
- package/dist/routes/sessions.js +628 -0
- package/dist/routes/sessions.js.map +1 -0
- package/dist/routes/system-messages.d.ts +2 -0
- package/dist/routes/system-messages.d.ts.map +1 -0
- package/dist/routes/system-messages.js +146 -0
- package/dist/routes/system-messages.js.map +1 -0
- package/dist/routes/tools.d.ts +2 -0
- package/dist/routes/tools.d.ts.map +1 -0
- package/dist/routes/tools.js +79 -0
- package/dist/routes/tools.js.map +1 -0
- package/package.json +63 -0
|
@@ -0,0 +1,354 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: cortex-bench
|
|
3
|
+
description: Multi-model parallel benchmark methodology for finding harness deficiencies and driving autoresearch-style recursive self-improvement of the CORTEX harness itself. Cross-provider comparison with ground-truth control. EVERY run must produce a deficiency ledger; experiments are git-worktree-isolated; visual/TUI output is evaluated via tmux capture; NEVER use model='auto' routing when benchmarking models.
|
|
4
|
+
triggers:
|
|
5
|
+
- benchmark
|
|
6
|
+
- multi-model
|
|
7
|
+
- cross-provider
|
|
8
|
+
- harness audit
|
|
9
|
+
- recursive improvement
|
|
10
|
+
- recursive self-improvement
|
|
11
|
+
- auto-research
|
|
12
|
+
- autoresearch
|
|
13
|
+
- compare models
|
|
14
|
+
- ground truth
|
|
15
|
+
- cortex bench
|
|
16
|
+
- parallel benchmark
|
|
17
|
+
- find harness bugs
|
|
18
|
+
- git worktree
|
|
19
|
+
- tmux capture
|
|
20
|
+
- tui evaluation
|
|
21
|
+
- frontend design
|
|
22
|
+
---
|
|
23
|
+
|
|
24
|
+
# Cortex-Bench — Multi-Model Benchmark Methodology
|
|
25
|
+
|
|
26
|
+
Cross-provider benchmark technique for auditing the CORTEX harness and driving recursive iterative self-improvement. The core insight: **many apparent "model quality gaps" between providers are harness-side bugs, not model-side**. Only a side-by-side comparison catches them.
|
|
27
|
+
|
|
28
|
+
Proven to surface 7+ classes of harness bugs (the running deficiency trail lives in your `.cortex/bench/` ledgers + `research-backlog.jsonl`).
|
|
29
|
+
|
|
30
|
+
> ## ⚑ THREE NON-NEGOTIABLE OPERATING RULES (read before any benchmark)
|
|
31
|
+
>
|
|
32
|
+
> 1. **Every benchmark must produce a DEFICIENCY LEDGER, not a pass/fail.** Any agent benchmarking in the CORTEX harness runs tasks *in order to find and fix what's wrong with the harness*. The deliverable of every run is a structured list of (a) harness deficiencies found + their fix, (b) model-disposition gaps to address via prompts/tool-defs/system-msgs, and (c) what was verified clean. A run that ends "all arms agree, looks good" is a wasted run — the task wasn't hard enough or wasn't real-work. Mine every run for deltas.
|
|
33
|
+
>
|
|
34
|
+
> 2. **NEVER use `model='auto'` / the model router when benchmarking models.** Benchmarking *measures a specific model*, so you must PIN it (`cortex -m <model>` / `Task model='<exact-id>'`). `'auto'` routes to a possibly-different model per task type, silently swapping the variable you're measuring and destroying the comparison. Worse, the router *learns from these runs* (`MODEL_ROUTER_RECORD`), so an auto-routed benchmark poisons the matrix with mislabeled data. The router is for production dispatch; the bench is for controlled measurement. Keep them apart.
|
|
35
|
+
>
|
|
36
|
+
> 3. **The eval is sacred — never game it.** The ground-truth control + the verifiable task is the fixed measuring stick (the `prepare.py` of this system). You may change the *harness*; you may never weaken the *check* to make a model/harness "pass." If a fix only passes by relaxing the verification, it's not a fix.
|
|
37
|
+
|
|
38
|
+
## The Core Methodology
|
|
39
|
+
|
|
40
|
+
```
|
|
41
|
+
Same exact prompt
|
|
42
|
+
├── Arm 1: CORTEX via model A (e.g., deepseek-v4-pro, Chat Completions API)
|
|
43
|
+
├── Arm 2: CORTEX via model B (e.g., claude-sonnet-4-6, Messages API)
|
|
44
|
+
├── Arm 3: CORTEX via model C (e.g., gemini-2.5-flash, GenerateContent API)
|
|
45
|
+
├── Arm 4+: More models covering more adapter paths
|
|
46
|
+
└── Control: Claude Code native sub-agent (Opus) — the ground-truth reference
|
|
47
|
+
|
|
48
|
+
↓
|
|
49
|
+
|
|
50
|
+
Compare all arms side-by-side across:
|
|
51
|
+
- Correctness vs control
|
|
52
|
+
- Tool call counts (thrashing?)
|
|
53
|
+
- Empty/dropped content
|
|
54
|
+
- Duplicate blocks
|
|
55
|
+
- 400 errors in server logs
|
|
56
|
+
- Cache hit rates
|
|
57
|
+
- Latency and cost
|
|
58
|
+
|
|
59
|
+
↓
|
|
60
|
+
|
|
61
|
+
Discrepancies → harness bugs OR model disposition differences
|
|
62
|
+
Harness bugs → fix → harness improves → re-benchmark
|
|
63
|
+
Model differences → document → improve prompts/tool defs/system msgs
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
## Cardinal Rules (learned the hard way)
|
|
67
|
+
|
|
68
|
+
1. **n ≥ 2, different tasks.** One task agreeing three ways is a false positive. Run at least two different tasks in fresh sessions.
|
|
69
|
+
2. **Ground-truth against the real artifact, not an agent.** The parallel sub-agent is a reference that fails differently, not an oracle. The only truth is direct shell/grep/python on actual files. **Existence/resolution claims need a behavioral probe**: an agent asserting "X is registered / X resolves / the alias works" must demonstrate it (run the lookup, hit the endpoint) — in a live audit, 2 of 6 agents asserted a nonexistent alias from a comment they'd read, and only the probe refuted it (which then exposed a real bug).
|
|
70
|
+
3. **Fresh server + fresh session per model probe.** `--new` on every prompt; restart the server between models. Prompt cache and debug logs bleed across models.
|
|
71
|
+
4. **Discard confounded runs.** After every run: `grep -nE "429|capacity|exhausted|rate.?limit|overloaded|quota" /tmp/cortex-server.log`. If it hits, the model was throttled, not benchmarked. Throw it away.
|
|
72
|
+
5. **Real work surface, not toy prompts.** The task must (a) move the harness/platform forward AND (b) have an independently verifiable answer. "Count imports in file X" is verifiable but worthless; "refactor module Z" is real but unverifiable. Find tasks that are BOTH.
|
|
73
|
+
6. **Pin the model — never `auto`.** See operating rule #2. When the variable under test IS the model, routing must be off and the model explicit. Auto-routing during a model benchmark is a methodology error that also corrupts the router matrix.
|
|
74
|
+
7. **Output is a deficiency ledger.** See operating rule #1. End every run by writing the findings to `.cortex/bench/<round>-<tag>.md` AND appending durable harness deficiencies to the `ResearchBacklog` (`.cortex/research-backlog.jsonl`). No ledger → the run didn't happen.
|
|
75
|
+
|
|
76
|
+
## Server Setup for Benchmarking
|
|
77
|
+
|
|
78
|
+
```bash
|
|
79
|
+
# Kill old server (match REAL argv — "node dist/index.js" not the full path)
|
|
80
|
+
pkill -9 -f "node dist/index.js" 2>/dev/null; sleep 2
|
|
81
|
+
ps -eo pid,args | grep "[d]ist/index.js" && echo "ZOMBIE — kill -9" || echo "clean"
|
|
82
|
+
|
|
83
|
+
# Start stateless (CRITICAL — persistent mode leaks context across probes)
|
|
84
|
+
cd packages/server && \
|
|
85
|
+
DEBUG=true \
|
|
86
|
+
MENTORSHIP_ENABLED=false \
|
|
87
|
+
ENABLE_SERVER_SIDE_TOOLS=true \
|
|
88
|
+
XAI_API_MODE=messages \
|
|
89
|
+
CORTEX_MODE=stateless \
|
|
90
|
+
setsid nohup node dist/index.js > /tmp/cortex-server.log 2>&1 < /dev/null &
|
|
91
|
+
|
|
92
|
+
# Poll for boot (~20s cold, not 5s)
|
|
93
|
+
for i in $(seq 1 30); do sleep 2; curl -sf http://localhost:4000/health >/dev/null && break; done
|
|
94
|
+
|
|
95
|
+
# Verify isolation: two identical probes must give DIFFERENT conversationId, SAME inputTokens
|
|
96
|
+
curl -s http://localhost:4000/v1/messages -H "Content-Type: application/json" \
|
|
97
|
+
-d '{"model":"deepseek-v4-pro","messages":[{"role":"user","content":"say hi"}],"max_tokens":50}' | python3 -c "import json,sys; r=json.load(sys.stdin); print(r.get('metadata',{}).get('conversationId','MISSING')[:8])"
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
## The Prompt Template
|
|
101
|
+
|
|
102
|
+
Craft a task that is:
|
|
103
|
+
- **Deterministic**: file contents, code patterns, counts — anything verifiable
|
|
104
|
+
- **Multi-step**: forces 3-15 tool calls (exercises tool loop, budget signals, error recovery)
|
|
105
|
+
- **Specific**: asks for exact line numbers, code quotes, structured output
|
|
106
|
+
|
|
107
|
+
Counter-examples (don't use): web content (varies by time), creative writing (no ground truth), single-file reads (too simple, bypasses loop).
|
|
108
|
+
|
|
109
|
+
## Running the Benchmark (Parallel Dispatch)
|
|
110
|
+
|
|
111
|
+
From within a Claude Code session, dispatch ALL arms in ONE message for true parallelism:
|
|
112
|
+
|
|
113
|
+
```
|
|
114
|
+
Task sub-agent 1: model=deepseek-v4-flash, prompt="[TASK TEXT]"
|
|
115
|
+
Task sub-agent 2: model=deepseek-v4-pro, prompt="[TASK TEXT]"
|
|
116
|
+
Task sub-agent 3: model=claude-sonnet-4-6, prompt="[TASK TEXT]"
|
|
117
|
+
Task sub-agent 4: model=gemini-2.5-flash, prompt="[TASK TEXT]"
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
Or via the cortex CLI + Task agents mixed:
|
|
121
|
+
```bash
|
|
122
|
+
# In one bash call, launch cortex + Claude Code sub-agent concurrently:
|
|
123
|
+
cortex --new --quiet -m deepseek-v4-pro "[TASK]" &
|
|
124
|
+
# + Task agent with Opus as control
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
## The Comparison Table (copy this format)
|
|
128
|
+
|
|
129
|
+
| Metric | Arm A (model) | Arm B (model) | Arm C (model) | Control (Opus) | Verdict |
|
|
130
|
+
|--------|---------------|---------------|---------------|----------------|---------|
|
|
131
|
+
| Turns | | | | | |
|
|
132
|
+
| Tool calls | | | | | |
|
|
133
|
+
| Tool pattern | | | | | |
|
|
134
|
+
| File path | | | | | |
|
|
135
|
+
| Key answer 1 | | | | | |
|
|
136
|
+
| Key answer 2 | | | | | |
|
|
137
|
+
| Code blocks correct? | | | | | |
|
|
138
|
+
| Empty/dropped content? | | | | | |
|
|
139
|
+
| Errors? | | | | | |
|
|
140
|
+
| Duration | | | | | |
|
|
141
|
+
|
|
142
|
+
## Bug Patterns — What Each Discrepancy Means
|
|
143
|
+
|
|
144
|
+
| Symptom | Likely Harness Bug | Class |
|
|
145
|
+
|---------|-------------------|-------|
|
|
146
|
+
| Empty content / no text | Empty-response not retried (R18b), responses adapter wrong id field (R18c) | Adapter |
|
|
147
|
+
| Duplicate tool_use blocks | Streaming accumulator no dedup (R18a) | Streaming |
|
|
148
|
+
| 400 error in server log | Wrong param name for provider (R19/O-series), id prefix mismatch (R19e) | Adapter/Config |
|
|
149
|
+
| 404 on Responses path | Doubled endpoint (R27#1) | Routing |
|
|
150
|
+
| Model returns tool_use only, no text | Loop exits on tool-use-no-text (R29a) | Loop control |
|
|
151
|
+
| Model thrashing (15+ calls) | Wrong working directory (R44 ESM bug), budget signals too weak | Infrastructure |
|
|
152
|
+
| Cache hit rate flat ~0.5% | System prompt in moving user slot instead of stable system field (R28a-f) | Caching |
|
|
153
|
+
| Cross-turn model switch 400s | Cross-provider response_id leak (R20a) | State |
|
|
154
|
+
| All o-series models 400 | Missing max_completion_tokens param (R19) | Model card |
|
|
155
|
+
| Gemini multi-turn 400 | thoughtSignature stripped in canonical conversion (R19c/d) | Adapter |
|
|
156
|
+
|
|
157
|
+
## Performance Benchmarking Addendum
|
|
158
|
+
|
|
159
|
+
When comparing cost/latency (not just correctness), capture these fields from every `/v1/messages` response:
|
|
160
|
+
|
|
161
|
+
| Field | Why |
|
|
162
|
+
|-------|-----|
|
|
163
|
+
| `usage.inputTokens` | System message + history overhead |
|
|
164
|
+
| `usage.outputTokens` | Response size |
|
|
165
|
+
| `usage.cacheReadTokens` / `usage.cacheCreationTokens` | Cache effectiveness |
|
|
166
|
+
| `metadata.toolCallIterations` | Round-trips |
|
|
167
|
+
| Wall-clock (time the curl) | Latency |
|
|
168
|
+
|
|
169
|
+
**Caveats:**
|
|
170
|
+
- `usage.cost_in_usd_ticks` only exists on XAI Responses API path — don't compare cost from paths that don't emit it
|
|
171
|
+
- `usage.outputTokens` under-reported for Gemini and XAI Messages
|
|
172
|
+
- Fresh-session floor ≈ 16k input tokens (system messages + tool schemas)
|
|
173
|
+
|
|
174
|
+
## Recursive Auto-Research Self-Improvement (autoresearch-style)
|
|
175
|
+
|
|
176
|
+
The harness is now mature enough to **research and improve its own library, autonomously and recursively** — the same pattern as karpathy/autoresearch (an agent mutates code, runs a fixed eval, keeps-or-discards, repeats, indefinitely). Here the "model being trained" is **the CORTEX harness itself**, and the eval is this benchmark methodology.
|
|
177
|
+
|
|
178
|
+
### The autoresearch mapping (internalize this)
|
|
179
|
+
|
|
180
|
+
| autoresearch | this harness |
|
|
181
|
+
|---|---|
|
|
182
|
+
| `train.py` — the mutable code the agent edits | the harness source in `packages/` (NOT a single file → use git-worktree isolation, below) |
|
|
183
|
+
| `prepare.py` — fixed, read-only eval (the ground truth metric) | the cortex-bench task + ground-truth control. **Never modify the check to pass** (operating rule #3) |
|
|
184
|
+
| `program.md` — human-tuned instructions ("a super lightweight skill") | **THIS skill** + the system messages. The human iterates HERE; the agent iterates on the code |
|
|
185
|
+
| `val_bpb` — one comparable metric | the per-run score: correctness-vs-control + deficiency count + the perf fields (input/output tokens, cache hit rate, tool iterations, latency) |
|
|
186
|
+
| `results.tsv` — append-only experiment ledger | `.cortex/bench/<round>-<tag>.md` + `research-backlog.jsonl` + `router-matrix.jsonl` |
|
|
187
|
+
| keep/discard via `git reset` | merge the worktree if the re-bench improves + no regression; else drop the worktree |
|
|
188
|
+
| **simplicity criterion** | a harness fix that *deletes* code/complexity and still holds the benchmark is a top-tier win. Weigh complexity cost vs. improvement; reject ugly hacks for tiny gains |
|
|
189
|
+
| **NEVER STOP** (run until interrupted) | run round after round; do not pause to ask "should I continue?" — escalate task difficulty and keep mining (consistent with the operator's `execute, don't defer` rule) |
|
|
190
|
+
|
|
191
|
+
### The loop
|
|
192
|
+
|
|
193
|
+
```
|
|
194
|
+
0. SETUP: pick a round tag (e.g. r55-loopfix). Create an isolated worktree (below).
|
|
195
|
+
1. RUN BENCHMARK (multi-model, same task, models PINNED — no 'auto')
|
|
196
|
+
↓
|
|
197
|
+
2. COMPARE vs control → MINE the deficiency ledger (operating rule #1)
|
|
198
|
+
↓
|
|
199
|
+
3. CLASSIFY each finding:
|
|
200
|
+
├── Harness bug → FIX in the worktree (ONE coherent fix; scope-isolation prevents creep)
|
|
201
|
+
├── Model disposition difference → improve prompts / tool-defs / system msgs
|
|
202
|
+
└── Genuine model error → log it; nothing to fix in the harness
|
|
203
|
+
↓
|
|
204
|
+
4. REBUILD (npm run build) + RE-RUN the SAME benchmark in the worktree
|
|
205
|
+
↓
|
|
206
|
+
5. DECIDE: improved AND no regression on prior rounds' tasks?
|
|
207
|
+
├── yes → merge worktree → main; append the deficiency + fix to the memory ledger
|
|
208
|
+
└── no → drop the worktree (cheap discard); log "discard" + why
|
|
209
|
+
↓
|
|
210
|
+
6. Pick the NEXT task (harder, exercises newly-fixed paths) → goto 1. Until interrupted.
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
The harness converges: each round fixes bugs that masked real model differences, making the next round's comparisons cleaner. Eventually the only remaining discrepancies are genuine model-capability differences (addressed via prompting, not code).
|
|
214
|
+
|
|
215
|
+
### Git-worktree schema — use the native `WorkspaceManager` tool (this already exists)
|
|
216
|
+
|
|
217
|
+
autoresearch isolates by editing one file; we isolate by **one git worktree per experiment** — required here because (a) the harness is a whole monorepo, not one file, (b) **two agents share this working tree** (Claude Code + the CORTEX agent), so an in-place experimental edit corrupts the other's state, and (c) a failed experiment must be discardable in one command.
|
|
218
|
+
|
|
219
|
+
**Do NOT hand-roll raw `git worktree` — the harness ships the `WorkspaceManager` tool for exactly this** (the agent-team-workspace system, built 2026-02-13; there is even a "Git Worktree" *dispatch mode* = `WorkspaceManager` + team dispatch where each parallel agent gets its own worktree). Native CORTEX agents call the tool; it wraps the git mechanics:
|
|
220
|
+
|
|
221
|
+
| `WorkspaceManager` action | what it runs | returns |
|
|
222
|
+
|---|---|---|
|
|
223
|
+
| `create` | `git worktree add /tmp/workspace-{uuid} -b {branch} {baseBranch}` | `{ worktreePath, branch, baseBranch, repoPath }` |
|
|
224
|
+
| `status` | `git worktree list --porcelain` | `{ worktreeCount, worktrees: [{path,head,branch}] }` |
|
|
225
|
+
| `diff` | `git diff {baseBranch} -- .` | `{ changedFiles, fileCount, diffLines, diff }` |
|
|
226
|
+
| `cleanup` | remove the worktree | — |
|
|
227
|
+
| `clone` | `git clone --depth 50` external repo (+ optional worktree) | `{ cloneDir, worktreePath, branch, repo }` |
|
|
228
|
+
|
|
229
|
+
Experiment loop with the tool:
|
|
230
|
+
1. `WorkspaceManager create` (branch `cortex-exp/<round>`) → isolated `worktreePath`.
|
|
231
|
+
2. **build INSIDE that worktree** (`cd <worktreePath> && npm install && npm run build`) — each worktree is its own checkout with its own `dist/`; never share `dist/`.
|
|
232
|
+
3. run the experiment server on a **non-default port** (4100, 4101, …) so it doesn't collide with the operator's live :4000.
|
|
233
|
+
4. bench against the experiment port, mine deficiencies, apply **one** coherent fix, rebuild, re-bench. Use `WorkspaceManager diff` to review the experiment's full change set before deciding.
|
|
234
|
+
5. **KEEP** (improved + no regression) → merge the branch to main, then `WorkspaceManager cleanup`. **DISCARD** → `WorkspaceManager cleanup` + delete the branch (cheap revert — the autoresearch keep/discard step).
|
|
235
|
+
|
|
236
|
+
Rules: **one fix per worktree** (scope-isolation = autoresearch's single-file constraint); parallel experiments = multiple worktrees on different ports; the keep/discard decision is the only thing that touches `main`.
|
|
237
|
+
|
|
238
|
+
*(Direct shell equivalents, if you're driving without the tool — e.g. a Claude Code session: `git worktree add -b cortex-exp/<round> /tmp/cortex-exp-<round> <base>` → build → bench on :4100 → `git merge --no-ff` or `git worktree remove --force` + `git branch -D`.)*
|
|
239
|
+
|
|
240
|
+
### The deficiency backlog — auto-add via the `ResearchBacklog` tool
|
|
241
|
+
|
|
242
|
+
The deficiency ledger (operating rule #1) is now a **tracked, triaged task lifecycle**, not just prose. Every deficiency found → `ResearchBacklog` tool, `action:add` (auto-triages + computes priority on add). The harness identifies its own weaknesses, prioritizes them, and works the highest-priority one next.
|
|
243
|
+
|
|
244
|
+
- **Triage / priority** = `(severityWeight × impact × confidence) ÷ effort`. Low-confidence "deficiencies" (could be model noise) sink automatically — the triage-layer overfitting guard.
|
|
245
|
+
- **Lifecycle**: `open → triaged → in_progress → fixed → verified → closed` (+ `wont_fix`, `regressed`). `action:next` returns the top-priority open item — the recursion's "what to fix next."
|
|
246
|
+
- **OVERFITTING GUARD in the status model**: `action:fixed` = passes the task that *surfaced* it; `action:verified` = ALSO holds on **held-out** tasks. **Never `verified` without held-out confirmation** — `fixed` is not done.
|
|
247
|
+
- Store: `.cortex/research-backlog.jsonl` (append-only, two-agent safe). The matrix (`router-matrix.jsonl`) holds the *scores*; the backlog holds the *work items*; they share `harnessRef`/`taskFingerprint` provenance.
|
|
248
|
+
|
|
249
|
+
### Overfitting guards (the recursion's immune system)
|
|
250
|
+
|
|
251
|
+
Recursive self-improvement's failure mode is **gaming the eval** — the harness tuned to pass the benchmark tasks rather than genuinely improving. Guards, layered:
|
|
252
|
+
1. **Held-out split.** Mark validation runs `CORTEX_BENCH_HOLDOUT=true` (→ `split:'holdout'` on matrix records). **Keep/discard uses `train`; verification uses `holdout`.** A fix tuned against task T is only `verified` when it improves *other* tasks it never saw.
|
|
253
|
+
2. **`fixed` ≠ `verified`.** The backlog enforces it structurally — no held-out pass, no verification.
|
|
254
|
+
3. **Confidence-weighted triage.** Noise-suspect findings are deprioritized, not chased.
|
|
255
|
+
4. **n ≥ 2 + significance.** LLM benchmarks are noisy; a single-run delta is often noise. Never "keep" on a delta within run-to-run variance (cardinal rule #1).
|
|
256
|
+
5. **Rotate the task pool.** Don't re-use the same handful of tasks every round; a fixed eval set invites overfitting. Real-work-surface tasks (cardinal rule #5) + rotation keep the eval honest.
|
|
257
|
+
6. **Regression scan across a broad set**, not just the target task — a "fix" that helps T while quietly hurting U is a discard.
|
|
258
|
+
|
|
259
|
+
### External / official benchmarks (SWE-bench etc.) — same pipeline, different source
|
|
260
|
+
|
|
261
|
+
The pipeline is **benchmark-source-agnostic**: `BenchmarkRecord.benchmarkSource` (env `CORTEX_BENCH_SOURCE`, default `cortex-bench`) lets official benchmarks feed the SAME matrix + backlog. An external runner (e.g. SWE-bench) records under `benchmarkSource:'swebench'`, the instance id as `taskFingerprint`, and pass/score from *its* grader — then auto-adds deficiencies for instances the harness fails. So SWE-bench / aider-polyglot / terminal-bench become additional ground-truth lenses pinpointing harness weaknesses, scored on the same axes, gated by the same overfitting/held-out discipline. (External runs are *excellent* held-out sets — the harness was never tuned against them.)
|
|
262
|
+
|
|
263
|
+
### North-star: a public verifiable record (SpacetimeDB)
|
|
264
|
+
|
|
265
|
+
The three local append-only stores — `router-matrix.jsonl` (scores), `research-backlog.jsonl` (work items), and `experiments.jsonl` (keep/discard decisions) — are **deliberately shaped to map onto STDB tables**: each is an append-only event stream keyed by `(taskFingerprint, modelId, harnessRef)` / `deficiency id` / `experimentTag`. Promoting them to a SpacetimeDB module would give a **public, verifiable, tamper-evident record** of the harness's self-improvement — every score, deficiency, and keep/discard decision auditable with commit provenance. (That public-record module lives in a separate service; the JSONL schemas here are the local mirror that ports up.)
|
|
266
|
+
|
|
267
|
+
### The decision layer is BUILT — call it, don't hand-judge keep/discard
|
|
268
|
+
|
|
269
|
+
As of 2026-06-07 the keep/discard decision is a **statistically-gated, reproducible** pipeline in `@nexus-cortex/core` (commits `ab9eb0b37`·`f7fc7e5c2`·`ec0f47551`·`825ada395`·`adb927987`). Do NOT eyeball "score went up → keep" — that overfits a recursive loop. Use:
|
|
270
|
+
- **`evaluateAutoResearchExperiment(matrix, ledger, input)`** — runs regressionScan → opens the ledger record → the Monte-Carlo gate → writes the audited verdict to `.cortex/experiments.jsonl`. `input = {experimentTag, baseRef, candidateRef, branch, deficiencyId?, benchmarkSource?, modelId?, nFamilyExperiments?, gate?, epsilon?}`. A 'keep' that introduced collateral regressions is flagged in the recorded reason.
|
|
271
|
+
- **`verifyOnHoldout(matrix, input)`** — the mandatory 2nd gate on `split='holdout'`; a candidate merges ONLY if kept-on-train AND verified-on-holdout (`fixed` ≠ `verified`; null = no held-out evidence = not mergeable).
|
|
272
|
+
- The gate = bootstrap CI (keep iff CI excludes 0) + permutation p-value + **N-aware FWER** (pass `nFamilyExperiments` = swarm width so the keep bar tightens with parallelism). Seeded RNG → **reproducible verdicts** (same records + seed = same p/CI), which is what makes the future STDB record publicly verifiable. Pure stats also exported: `decideExperiment`, `bootstrapCI`, `permutationPValue`, `sidakThreshold`, `mcFwerThreshold`.
|
|
273
|
+
- Optional **Thompson-sampling router** (`MODEL_ROUTER_EXPLORATION=true`) for explore/exploit so the matrix doesn't lock onto early winners. Off by default.
|
|
274
|
+
|
|
275
|
+
**Producing REAL scored records — `cortex autoresearch bench` (the grader).** The orchestrator's auto-record (`MODEL_ROUTER_RECORD`) writes only a liveness STUB (`qualitativeScore = hasText ? 75 : 0`) — useless for keep/discard (base ≈ candidate → always discard). To get real signal, run a graded task set:
|
|
276
|
+
```
|
|
277
|
+
cortex autoresearch bench --task-set <file|dir of *.json> --experiment-tag <id> \
|
|
278
|
+
--runs 2 --split train|holdout [--harness-ref <sha>] [--model <id>]
|
|
279
|
+
```
|
|
280
|
+
Task = `{id, prompt, verifier, taskType?}`; verifier ∈ `exact|regex|contains|llm-judge`. **Prefer `contains` (partial credit → continuous score) or graded rubrics** over binary exact/regex — the bootstrap/permutation gate separates arms far better on continuous scores. Sample: `.cortex/bench/tasks/sample-tasks.json`. Run it in the base build and the candidate build (different `--harness-ref`/worktree), then `cortex autoresearch evaluate`. Keep holdout task FILES out of any fixing agent's context (overfitting guard).
|
|
281
|
+
|
|
282
|
+
**The one-shot runner — `cortex autoresearch experiment` (v4.7.0).** Does the whole single-experiment loop in one call (build+serve both arms → bench train+holdout → gate → `verifyOnHoldout` → teardown), so you don't orchestrate `bench`×2 + `evaluate` by hand:
|
|
283
|
+
```
|
|
284
|
+
cortex autoresearch experiment --experiment-tag <id> \
|
|
285
|
+
--candidate-dir <worktree-with-fix> --base-dir <prebuilt base> \
|
|
286
|
+
--task-set <train.json> [--holdout-set <holdout.json>] \
|
|
287
|
+
--model <id> --runs 3 --n-family <swarm-width> --cortex-dir <per-exp dir> --json
|
|
288
|
+
```
|
|
289
|
+
`--json` → `{verdict, holdoutVerdict, regressedTasks, mergeEligible, benchSummaries, cortexDir, jsonlPaths}`. Owns the "two builds not one relabel" correctness (each arm served from its OWN built code; refuses `baseRef===candidateRef`). `--cortex-dir` is the per-experiment **artifact** (all 3 `.cortex/*.jsonl`). `mergeEligible` = keep ∧ fwerAdjusted ∧ holdout-keep (FALSE without holdout). Validated live end-to-end (both a real **discard** and a real **keep** with `mergeEligible:true`).
|
|
290
|
+
|
|
291
|
+
### Hard-won benchmarking gotchas (from the first live runs, 2026-06-08)
|
|
292
|
+
- **Server returns `model` as an OBJECT** `{id, provider}`, not a string — any recorder must extract `.id` (fixed in serverRunner/estimateCost, `a4097aaf8`).
|
|
293
|
+
- **`PROJECT_PATH`, not `PROJECT_ROOT`**, controls the orchestrator's project context (system messages, CORTEX.md, agents) — set it when spawning a harness for a specific checkout (fixed in startServer, `3f549daa5`).
|
|
294
|
+
- **System-message resolution is project → global → builtin.** A candidate that edits a **built-in/`dist`** system message is **shadowed by `~/.cortex` (global)** and has NO effect. To change harness behavior, override at the **PROJECT** level (`<dir>/.cortex/system-messages/` or `<dir>/.cortex/CORTEX.md`) — that wins over global. (System-message injection itself WORKS — confirmed ~72K chars incl. CORTEX.md reach the model.)
|
|
295
|
+
- **Markers/format tokens are an UNRELIABLE signal** — low-compliance models (e.g. deepseek-v4-flash) ignore a format rule buried in a 72K system prompt even when it's present. For a measurable base-vs-candidate signal, use a **high-compliance model** (e.g. `claude-haiku-4-5`) and a **strong directive** (e.g. "respond only with JSON `{\"answer\":…}`") with a verifier that checks it. That's what produced the clean keep proof.
|
|
296
|
+
|
|
297
|
+
### Model-selection discipline while benchmarking (no-xAI cost constraint)
|
|
298
|
+
Default sub-agent model is **deepseek** (`DEFAULT_SUBAGENT_MODEL=deepseek-v4-flash`; `recommend()` fallback is deepseek too — no grok/sonnet defaults). The auto-router (Thompson exploration) honors `MODEL_ROUTER_EXCLUDE` (default `grok*`, a prefix wildcard) so it can NEVER auto-route a sub-agent to an xAI model. This is a guardrail on *automatic* picks only — an **explicit** model choice (driver `DEFAULT_MODEL_ID`, `/model`, an agent profile's pinned model, or the Task tool's `model` param) is always honored, including xAI/expensive-Claude. When benchmarking specific models, name them explicitly and never rely on `'auto'` (per the deficiency-first rule above).
|
|
299
|
+
|
|
300
|
+
### Composing skills inside the loop
|
|
301
|
+
- **The FIX step can be a `best-of-n` tournament.** A high-value deficiency justifies N competing fixes instead of one: one worktree per entrant, distinct strategy/model/temperature per arm (pass `strategy`/`temperature` on the Task dispatch — recorded into the matrix), criteria frozen before launch, one central judge. The re-bench IS the tournament's acceptance check.
|
|
302
|
+
- **The VERIFY step is `verify-work`.** Before a keep decision, run its refute-don't-confirm checklist on the candidate: independent verifier that never saw the fix reasoning, evidence-based per-claim verdicts, blast-radius scan. The statistical gate (`evaluate`) and the structural verifier catch different failure modes — use both.
|
|
303
|
+
- **The document skills (`docx`/`xlsx`/`pptx`/`pdf-documents`) are ready-made bench-task surfaces.** "Produce a workbook with these computed columns / a deck with these sections" is real work with a deterministic verifier (re-open the file, assert contents) — exactly the real-work-surface + independently-verifiable pair that cardinal rule #5 demands, and a graded `contains`/`numeric` task-set can check the extracted content.
|
|
304
|
+
|
|
305
|
+
## Visual / TUI Evaluation via tmux (for CLI/TUI frontend-design benchmarks)
|
|
306
|
+
|
|
307
|
+
Most benchmarks compare JSON from `/v1/messages` — but that **cannot see what a human sees**. When the thing under test is *rendered output* — markdown formatting (tables, code fences, lists), the Ink TUI's layout, colors, alignment, spinners, wrapping, the thinking/tool-call panes — you must evaluate the **actual terminal render**, not the raw model text. A model can emit perfect markdown that the TUI then mangles; only a capture shows it.
|
|
308
|
+
|
|
309
|
+
**Use the native `TmuxSession` tool** (proven method — same one used during the earlier active-improvement rounds; it wraps `TmuxCapture.ts`/`TmuxManager.ts`, stores metadata in `.cortex/tmux-sessions/`, binary via `TMUX_BIN`). The tool exposes **create → send commands → capture output → list → kill**. The agentic flow:
|
|
310
|
+
|
|
311
|
+
1. `TmuxSession create` — a persistent session sized like a real terminal (e.g. 200×50; also test 80×24 — different widths expose different wrapping/overflow bugs).
|
|
312
|
+
2. `TmuxSession send` → from the repo root, launch the TUI (e.g. `neoncortex`, the Ink UI; or `cortex-cli`). Wait for boot.
|
|
313
|
+
3. `TmuxSession send` → the prompt that exercises the rendering under test (e.g. *"Show a markdown table of the 5 cheapest models with a fenced code example"*). Wait for the stream to finish.
|
|
314
|
+
4. `TmuxSession capture` — **this captured pane IS the metric.** It's the human-visible truth; the raw model text is NOT (a model can emit perfect markdown the TUI then mangles — only the capture shows it).
|
|
315
|
+
5. Evaluate the capture for **frontend-design deficiencies**, treating the render as a real UI surface (hierarchy, alignment, contrast, density — not just "did text appear"):
|
|
316
|
+
- markdown table aligned / borders intact? code fence syntax-highlighted vs. raw backticks?
|
|
317
|
+
- wrapping at the pane width, or overflow / truncation?
|
|
318
|
+
- colors readable, spacing/padding sane, no doubled/garbled lines?
|
|
319
|
+
- thinking & tool-call panes legible and not stealing the answer's space?
|
|
320
|
+
6. Fix the TUI renderer (in the TUI package, where installed), rebuild, **re-capture, diff before/after** — same keep/discard discipline as the code loop. `TmuxSession kill` when done.
|
|
321
|
+
|
|
322
|
+
*(Direct shell equivalent without the tool: `tmux new-session -d -s T -x 200 -y 50` → `tmux send-keys -t T '…' Enter` → `tmux capture-pane -p -e -t T > render.txt` (`-e` keeps ANSI color) → inspect → `tmux kill-session -t T`.)*
|
|
323
|
+
|
|
324
|
+
## Quick-Start (copy-paste into a session)
|
|
325
|
+
|
|
326
|
+
```
|
|
327
|
+
I need a multi-model benchmark. Pick a specific task:
|
|
328
|
+
|
|
329
|
+
TASK: "In this repo, find [specific file/function]. Report: (a) path,
|
|
330
|
+
(b) complete implementation, (c) [specific detail], (d) [edge case behavior].
|
|
331
|
+
Be precise, cite line numbers."
|
|
332
|
+
|
|
333
|
+
Dispatch arms:
|
|
334
|
+
- Arm A: model=deepseek-v4-pro, same prompt
|
|
335
|
+
- Arm B: model=claude-sonnet-4-6, same prompt
|
|
336
|
+
- Arm C: model=claude-haiku-4-5, same prompt
|
|
337
|
+
- Control: I (Opus) will answer directly
|
|
338
|
+
|
|
339
|
+
Then compare all 4 answers side-by-side and report discrepancies.
|
|
340
|
+
```
|
|
341
|
+
|
|
342
|
+
## Location Reference
|
|
343
|
+
|
|
344
|
+
(paths are relative to the repo root)
|
|
345
|
+
|
|
346
|
+
- Server: `packages/server/dist/index.js`
|
|
347
|
+
- Server log: `/tmp/cortex-server.log`
|
|
348
|
+
- Bench results / deficiency ledgers: `.cortex/bench/`
|
|
349
|
+
- Routing matrix (the metric store): `.cortex/router-matrix.jsonl`
|
|
350
|
+
- Deficiency backlog (the work-item ledger): `.cortex/research-backlog.jsonl`
|
|
351
|
+
- **Worktree/team proven pattern:** the `WorkspaceManager` tool (core: `tools/definitions/`, executor: `executors/.../execution/`)
|
|
352
|
+
- **TUI capture proven pattern:** the `TmuxSession` tool, `TmuxCapture.ts` / `TmuxManager.ts`, sessions in `.cortex/tmux-sessions/`
|
|
353
|
+
- The project `CLAUDE.md` is the full tool & subsystem reference (tools like `TmuxSession`, `WorkspaceManager`, the adapter map, the registries).
|
|
354
|
+
- Auto-research inspiration: the "evolve code → fixed eval → keep/discard → repeat" loop — a fixed eval (`prepare.py` analog) ≙ the ground-truth control; the mutable code (`train.py` analog) ≙ the harness, worktree-isolated; this skill is the human-tuned `program.md` analog.
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: docx
|
|
3
|
+
description: >
|
|
4
|
+
Create, read, and edit Word documents (.docx). Use whenever the deliverable is
|
|
5
|
+
a Word document, or the user asks to open/modify/extract from an existing
|
|
6
|
+
.docx — reports, letters, templated documents, doc-to-PDF conversion. The
|
|
7
|
+
deliverable must be a .docx (or a PDF derived from one); do not trigger when
|
|
8
|
+
plain markdown or HTML is the requested output.
|
|
9
|
+
metadata:
|
|
10
|
+
short-description: "Create, read, and edit Word (.docx) documents"
|
|
11
|
+
author: "nexus-cortex"
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
# DOCX — Word Documents
|
|
15
|
+
|
|
16
|
+
Work with .docx files using open-source tooling. A .docx is a ZIP of XML parts —
|
|
17
|
+
never hand-edit the XML when a library can do it safely.
|
|
18
|
+
|
|
19
|
+
## Tooling (pick by job)
|
|
20
|
+
|
|
21
|
+
| Job | Tool | Notes |
|
|
22
|
+
|-----|------|-------|
|
|
23
|
+
| Create / edit programmatically | `python-docx` | Paragraphs, runs, styles, tables, images, headers/footers, sections |
|
|
24
|
+
| Fill a template with data | `docxtpl` | Jinja2 placeholders inside a .docx template — best for repeated/templated docs |
|
|
25
|
+
| Markdown/HTML → docx | `pandoc` | `pandoc in.md -o out.docx` (use `--reference-doc=style.docx` for branding) |
|
|
26
|
+
| Extract text quickly | `python-docx` walk, or `pandoc out.docx -t plain` | For search/summarize jobs |
|
|
27
|
+
| docx → PDF | LibreOffice headless | `soffice --headless --convert-to pdf file.docx --outdir out/` |
|
|
28
|
+
|
|
29
|
+
Install on demand: `pip install python-docx docxtpl` (don't assume preinstalled).
|
|
30
|
+
|
|
31
|
+
## Core patterns (python-docx)
|
|
32
|
+
|
|
33
|
+
```python
|
|
34
|
+
from docx import Document
|
|
35
|
+
from docx.shared import Pt, Inches, RGBColor
|
|
36
|
+
from docx.enum.text import WD_ALIGN_PARAGRAPH
|
|
37
|
+
|
|
38
|
+
doc = Document() # or Document("existing.docx") to edit
|
|
39
|
+
doc.add_heading("Quarterly Report", level=1)
|
|
40
|
+
|
|
41
|
+
p = doc.add_paragraph("Revenue grew ")
|
|
42
|
+
run = p.add_run("18%") # runs carry character formatting
|
|
43
|
+
run.bold = True
|
|
44
|
+
|
|
45
|
+
table = doc.add_table(rows=1, cols=3)
|
|
46
|
+
table.style = "Light Grid Accent 1"
|
|
47
|
+
hdr = table.rows[0].cells
|
|
48
|
+
hdr[0].text, hdr[1].text, hdr[2].text = "Region", "Q1", "Q2"
|
|
49
|
+
|
|
50
|
+
doc.add_picture("chart.png", width=Inches(5.5))
|
|
51
|
+
doc.save("report.docx")
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
Editing an existing document: iterate `doc.paragraphs` / `doc.tables`, modify
|
|
55
|
+
`run.text` in place (replacing at the **run** level preserves formatting;
|
|
56
|
+
replacing `paragraph.text` wholesale destroys it). For find-and-replace across
|
|
57
|
+
runs, match on the concatenated paragraph text but write back run-by-run.
|
|
58
|
+
|
|
59
|
+
## Styles and structure
|
|
60
|
+
|
|
61
|
+
- Prefer **named styles** (`doc.styles`) over per-run formatting — consistent
|
|
62
|
+
and editable later. Set `style="Heading 2"` / `p.style = doc.styles["Quote"]`.
|
|
63
|
+
- Page setup lives on `doc.sections[0]` (margins, orientation, headers/footers).
|
|
64
|
+
- Numbered/bulleted lists: apply the `List Number` / `List Bullet` styles.
|
|
65
|
+
|
|
66
|
+
## Verification (mandatory)
|
|
67
|
+
|
|
68
|
+
The deliverable is the FILE, so verify the file, not your intent:
|
|
69
|
+
1. **Re-open it** with `Document("out.docx")` — a corrupt file throws here.
|
|
70
|
+
2. **Assert the content**: walk paragraphs/tables and check the key strings,
|
|
71
|
+
counts, and ordering you were asked to produce.
|
|
72
|
+
3. If converting to PDF, check the PDF exists and is non-trivial in size, and
|
|
73
|
+
render/read at least one page when the layout matters.
|
|
74
|
+
|
|
75
|
+
## Limits to know
|
|
76
|
+
|
|
77
|
+
- `python-docx` does not evaluate fields (TOC, page numbers) — they refresh
|
|
78
|
+
when the document opens in Word/LibreOffice. To force-update a TOC, convert
|
|
79
|
+
with LibreOffice once.
|
|
80
|
+
- Tracked changes and comments have limited library support — when asked to
|
|
81
|
+
"accept changes", convert via LibreOffice or warn explicitly.
|
|
82
|
+
- Exotic layout (text boxes, SmartArt) round-trips poorly — preserve, don't
|
|
83
|
+
rebuild, those parts when editing.
|