Compare commits

..
243 Commits
Author SHA1 Message Date
Julian lechner 2192b4613d fix(ci): refresh agent metadata budget baselines
CI / CI configuration security checks (push) Successful in 3s
CI / Python tests and compilation (push) Successful in 23s
CI / QMD unit tests (push) Successful in 12s
CI / Build and inspect generated packages (push) Successful in 17s
CI / PowerShell tests on Ubuntu (push) Successful in 1m6s
CI / Installed client configuration smoke tests (push) Successful in 1m20s
CI / Capabilities and shell quality (push) Successful in 16s
CI / Bash integration and installation guards (push) Successful in 1m21s
2026-10-08 16:09:11 +02:00
Julian lechner 5e80d30936 fix(config): harden doctor checks and enable Codex full access
CI / CI configuration security checks (push) Successful in 3s
CI / Python tests and compilation (push) Successful in 25s
CI / QMD unit tests (push) Successful in 11s
CI / Build and inspect generated packages (push) Successful in 17s
CI / PowerShell tests on Ubuntu (push) Successful in 1m11s
CI / Installed client configuration smoke tests (push) Successful in 1m10s
CI / Capabilities and shell quality (push) Successful in 18s
CI / Bash integration and installation guards (push) Failing after 1m13s
2026-10-08 15:58:47 +02:00
Julian lechner 8aae370bdb fix(agents): align research tools and clarify role boundaries 2026-10-08 15:43:30 +02:00
Julian lechner 8288ea51f0 docs: refresh configuration guides and remove obsolete plans 2026-10-08 15:37:03 +02:00
Julian lechner 17d01d58f5 fix(ci): install YAML dependency for QMD unit tests 2026-10-08 15:30:23 +02:00
Julian lechner 7f441d388d fix(qmd): resolve hoisted dependencies from package context
CI / CI configuration security checks (push) Successful in 3s
CI / Python tests and compilation (push) Successful in 23s
CI / QMD unit tests (push) Failing after 11s
CI / Build and inspect generated packages (push) Successful in 17s
CI / PowerShell tests on Ubuntu (push) Successful in 1m2s
CI / Installed client configuration smoke tests (push) Successful in 1m7s
CI / Capabilities and shell quality (push) Successful in 15s
CI / Bash integration and installation guards (push) Successful in 1m17s
2026-10-08 15:25:33 +02:00
Julian lechner 88f7c9984b docs(instructions): explain conditional custom instruction loading
CI / CI configuration security checks (push) Successful in 3s
CI / Python tests and compilation (push) Successful in 23s
CI / QMD unit tests (push) Failing after 9s
CI / Build and inspect generated packages (push) Successful in 15s
CI / PowerShell tests on Ubuntu (push) Successful in 1m11s
CI / Installed client configuration smoke tests (push) Successful in 52s
CI / Capabilities and shell quality (push) Successful in 18s
CI / Bash integration and installation guards (push) Successful in 1m14s
2026-10-08 15:16:30 +02:00
Julian lechner b1170604eb fix(instructions): refresh startup rule when custom instructions change 2026-10-08 15:16:19 +02:00
Julian lechner 83091d247a fix(instructions): add startup rule only for existing custom instructions 2026-10-08 15:16:07 +02:00
Julian lechner 6a981bd7f2 fix(instructions): check optional personal file before reading 2026-10-08 15:02:05 +02:00
Julian lechner 73cb30c32b ci(qmd): keep model execution out of ci 2026-10-08 14:59:32 +02:00
Julian lechner 2fe612c8e1 fix(tests): expect codex session start hook in packages 2026-10-08 14:59:19 +02:00
Julian lechner 32283c428a docs(plugins): explain automatic triggers and opt-outs 2026-10-08 14:49:23 +02:00
Julian lechner 99d30163ce feat(skills): enforce automatic plugin workflow routing 2026-10-08 14:49:10 +02:00
Julian lechner 8e9b28ffb0 refactor(rules): shorten mandatory research guidance 2026-10-08 14:48:55 +02:00
Julian lechner 1cdb6b1881 refactor(image): retain focused SEO and performance guidance 2026-10-08 14:38:49 +02:00
Julian lechner 65c99ac76d feat(codex): show remaining usage and fast mode in status bar 2026-10-08 14:38:33 +02:00
Julian lechner 5c66f79a76 fix(hooks): initialize flashbang when its DLL cache is unavailable 2026-10-08 14:38:18 +02:00
Julian lechner 3586245408 feat(workflows): enforce research checkpoints across development phases 2026-10-08 14:38:05 +02:00
Julian lechner fe7a4d7a25 feat(research): require Context7 evidence for external behavior 2026-10-08 14:37:47 +02:00
Julian lechner fa43cb13ac docs(skills): explain mandatory research workflow
CI / CI configuration security checks (push) Successful in 3s
CI / Python tests and compilation (push) Successful in 24s
CI / Build and inspect generated packages (push) Successful in 42s
CI / PowerShell tests on Ubuntu (push) Failing after 1m27s
CI / Installed client configuration smoke tests (push) Successful in 40s
CI / Capabilities and shell quality (push) Successful in 17s
CI / Bash integration and installation guards (push) Failing after 20s
CI / QMD local search integration (push) Failing after 13m6s
2026-10-08 13:55:28 +02:00
Julian lechner 21e3352456 docs(rules): enforce research gates across workflows 2026-10-08 13:55:27 +02:00
Julian lechner d929c6df26 docs(skills): require primary evidence for every technical lookup 2026-10-08 13:55:27 +02:00
Julian lechner f497a23aaa docs(skills): apply semantic routing before every repository lookup 2026-10-08 13:55:26 +02:00
Julian lechner e12caa0d9f docs(skills): require research checks for every repository lookup 2026-10-08 13:55:26 +02:00
Julian lechner a1427f18a3 feat(skills): add mandatory research gate 2026-10-08 13:55:25 +02:00
Julian lechner 766f08af26 fix(codex): use elevated Windows sandbox 2026-10-08 13:55:24 +02:00
Julian lechnerandClaude Sonnet 5.5 c041521668 feat(codex): enable api_key_model_discovery feature
CI / CI configuration security checks (push) Successful in 3s
CI / Python tests and compilation (push) Successful in 22s
CI / Build and inspect generated packages (push) Successful in 27s
CI / PowerShell tests on Ubuntu (push) Failing after 1m7s
CI / Installed client configuration smoke tests (push) Successful in 1m9s
CI / Capabilities and shell quality (push) Successful in 15s
CI / Bash integration and installation guards (push) Failing after 24s
CI / QMD local search integration (push) Failing after 12m46s
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-08 13:11:58 +02:00
Julian lechnerandClaude Opus 5.5 3f51bc908e docs(skills): make technical research mandatory for unverified external behavior
CI / PowerShell tests on Ubuntu (push) Failing after 3s
CI / CI configuration security checks (push) Successful in 4s
CI / Python tests and compilation (push) Successful in 23s
CI / Build and inspect generated packages (push) Successful in 19s
CI / Installed client configuration smoke tests (push) Successful in 1m16s
CI / Capabilities and shell quality (push) Successful in 22s
CI / Bash integration and installation guards (push) Failing after 22s
CI / QMD local search integration (push) Failing after 12m46s
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 12:56:29 +02:00
Julian lechnerandClaude Opus 5.5 36851c34e2 docs(skills): hand semantic search hits to repository research
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 12:56:28 +02:00
Julian lechnerandClaude Opus 5.5 ede0c37d24 docs(skills): make repository research mandatory and route unknown identifiers to semantic search
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 12:56:28 +02:00
Julian lechnerandClaude Opus 5.5 b8ebe452bf chore(gitignore): ignore .NET build output of benchmark fixtures
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 12:54:08 +02:00
Julian lechnerandClaude Opus 5.5 1e93e1dad4 chore(gitignore): ignore Python bytecode caches
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 12:54:07 +02:00
Julian lechnerandClaude Opus 5.5 c0fa0961c3 docs(qmd): document the git ignore list in repository collections
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 12:48:09 +02:00
Julian lechnerandClaude Opus 5.5 06c4848336 fix(qmd): handle a lost daemon start race and stale daemon tokens
startDaemon accepts the daemon of another launch when its own child
exits 0. A 403 from the daemon marks daemon.json as stale: the wrapper
deletes it and starts a new daemon once.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 12:47:41 +02:00
Julian lechnerandClaude Opus 5.5 3012e1666e fix(qmd): let only one concurrent launch start the daemon
An exclusive daemon.lock (stale after 2 minutes) is held from before the
health check until the daemon listens; a launch that loses exits 0.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 12:47:03 +02:00
Julian lechnerandClaude Opus 5.5 691ad6a69f fix(qmd): skip git-ignored paths in repository collections
The daemon passes `git ls-files --others --ignored --directory` as
escaped ignore globs to addCollection. QMD's YAML write-through drops
`ignore` and index.yml wins on every re-sync, so the list is also
written into index.yml and re-synced whenever it changes.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 12:45:27 +02:00
Julian lechnerandClaude Opus 5.5 abface2293 fix(qmd): write index.yml atomically
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 12:42:40 +02:00
Julian lechnerandClaude Opus 5.5 ced6d8f119 fix(qmd): keep models loaded until the daemon's own idle exit
QMD 2.8.3 createStore unloads the models after 5 idle minutes, which
made the next search reload them.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 12:42:05 +02:00
Julian lechnerandClaude Opus 5.5 1618cd7cd0 docs(qmd): note the CLI fallback under the Codex sandbox
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 12:41:49 +02:00
Julian lechnerandClaude Opus 5.5 233152ff54 fix(qmd): honor XDG_CACHE_HOME for the setup-owned model files
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 12:41:42 +02:00
Julian lechnerandClaude Opus 5.5 7ebd61f35b fix(qmd): make removal wait for the daemon and survive partial failures
Removal reads the daemon PID before --stop and waits up to 10 s for it
to exit. A model file that cannot be deleted stays recorded in the state
for a retry instead of aborting removal, and a failing models block
restore only warns.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 12:41:19 +02:00
Julian lechnerandClaude Opus 5.5 0c203a3905 fix(qmd): stop the legacy Python daemon before removing its directory
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 12:40:37 +02:00
Julian lechnerandClaude Opus 5.5 f1d7894ba0 fix(qmd): treat Auto install and GPU probe failures as unsuitable
Auto now rolls back and reports "not suitable" when Node.js is too old,
npm or the model download fails. A failing GPU probe falls back to the
CPU in both Yes and Auto.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 12:40:12 +02:00
Julian lechnerandClaude Opus 5.5 60f739ceb9 fix(qmd): repair integration test, pull models first, reorder CI steps
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 12:19:18 +02:00
Julian lechnerandClaude Opus 5.5 5f21e4fb7c ci(qmd): replace the Qwen retrieval job with a QMD integration job
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 12:17:49 +02:00
Julian lechnerandClaude Opus 5.5 c31af49b70 docs(qmd): make semantic search mandatory and document QMD local search
Prompt budget stays within +10% of baseline (instruction 1485 -> 1331,
skill metadata 3163 -> 3017, rule catalog claude 28818 -> 30517); baseline
files unchanged.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 12:15:15 +02:00
Julian lechnerandClaude Opus 5.5 5bb0bdf62f refactor(retrieval): remove the Python Qwen stack and the QMD extension entry
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 12:12:22 +02:00
Julian lechnerandClaude Opus 5.5 505e6ae084 feat(install): ask for QMD local search models and run the QMD installer
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 12:10:19 +02:00
Julian lechnerandClaude Opus 5.5 953401a431 fix(qmd): reject unreliable npm listings and restore non-mapping models verbatim
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 11:55:47 +02:00
Julian lechnerandClaude Opus 5.5 7f89ae70bd fix(qmd): preserve user models block, adopt-and-remove ledger package, guard symlinks
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 11:53:22 +02:00
Julian lechnerandClaude Opus 5.5 59796d99d7 feat(qmd): install, benchmark, migrate, and remove QMD local search
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 11:49:22 +02:00
Julian lechnerandClaude Opus 5.5 29e712e751 fix(qmd): measure embed throughput after warm-up and fail on embed errors
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 11:47:48 +02:00
Julian lechnerandClaude Opus 5.5 d8a5ad7492 feat(qmd): add GPU and CPU benchmark for Auto selection
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 11:46:05 +02:00
Julian lechnerandClaude Opus 5.5 f483ea7fe7 fix(qmd): stop hook group growth on re-sync and harden the warm-up lock
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 11:44:18 +02:00
Julian lechnerandClaude Opus 5.5 f3c88a089e feat(qmd): warm the index and daemon from a SessionStart hook
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 11:37:47 +02:00
Julian lechnerandClaude Opus 5.5 08f015de92 fix(qmd): start the search daemon only when none runs and fail fast on child exit
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 11:29:05 +02:00
Julian lechnerandClaude Opus 5.5 a40ff270d8 feat(qmd): add search wrapper with daemon start and CLI fallback
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 11:25:28 +02:00
Julian lechnerandClaude Opus 5.5 f4dd193ea1 fix(qmd): harden daemon refresh, fingerprint, and request handling
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 11:23:55 +02:00
Julian lechnerandClaude Opus 5.5 cba9a7a2f4 feat(qmd): add token-protected search daemon with idle exit
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 11:16:52 +02:00
Julian lechnerandClaude Opus 5.5 1ad1880704 feat(qmd): add shared Node helpers and index.yml model block editing
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 11:15:08 +02:00
Julian lechnerandClaude Opus 5.5 c7c7c57621 docs(plans): simplify the warm-up step
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 11:10:18 +02:00
Julian lechnerandClaude Opus 5.5 76de4f8dab docs(plans): plan QMD local search implementation
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 11:10:04 +02:00
Julian lechnerandClaude Opus 5.5 6850ef5f2a docs(specs): run QMD search through an SDK daemon with expansion
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 11:03:03 +02:00
Julian lechnerandClaude Opus 5.5 6dd7cad9f5 docs(specs): design QMD as the local search engine
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 10:58:42 +02:00
Julian lechnerandClaude Opus 5.5 5b098fef70 test(benchmarks): phrase the transient retry prompt as a task
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 10:40:22 +02:00
Julian lechnerandClaude Opus 5.5 0779e5c7db fix(benchmarks): resume Codex sessions without the rejected --sandbox flag
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 10:40:21 +02:00
Julian lechnerandClaude Opus 5.5 af1e248243 fix(benchmarks): pass prompts through stdin so Windows rework turns keep newlines
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 10:40:21 +02:00
Julian lechnerandClaude Opus 5.5 e6b516f828 feat(benchmarks): summarize A/B results per task category
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 10:34:03 +02:00
Julian lechnerandClaude Opus 5.5 449ffa3631 test(benchmarks): tag tasks as small change, larger implementation, or search
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 10:34:02 +02:00
Julian lechnerandClaude Opus 5.5 56f9981cc9 docs(rules): merge repeated completion checks in definition of done
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 10:34:02 +02:00
Julian lechnerandClaude Opus 5.5 0af6b13a16 docs(rules): leave commented-out code to the definition of done
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 10:34:02 +02:00
Julian lechnerandClaude Opus 5.5 bd4d94e451 docs(rules): keep Java composition guidance in modern-java only
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 10:34:01 +02:00
Julian lechnerandClaude Opus 5.5 f4f38b38c9 docs(rules): give each C# rule statement one authoritative file
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 10:34:01 +02:00
Julian lechnerandClaude Opus 5.5 30257e72cd ci: fail PowerShell job when the runtime cannot be installed
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 10:34:00 +02:00
Julian lechnerandClaude Opus 5.5 f254a1ca40 fix(context-report): accept "< 20" token counts from /context
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 10:34:00 +02:00
Julian lechner a81c67f070 feat(semantic-search): report search cost before retrieval
CI / CI configuration security checks (push) Successful in 4s
CI / Python tests and compilation (push) Successful in 18s
CI / Build and inspect generated packages (push) Successful in 19s
CI / PowerShell tests on Ubuntu (push) Successful in 1m6s
CI / Installed client configuration smoke tests (push) Successful in 38s
CI / Qwen retrieval integration (push) Successful in 14m24s
CI / Capabilities and shell quality (push) Successful in 15s
CI / Bash integration and installation guards (push) Successful in 1m10s
2026-10-01 15:50:29 +02:00
Julian lechnerandClaude Opus 5.5 13220affb3 fix(install): drop unused variable flagged by shellcheck
CI / CI configuration security checks (push) Successful in 5s
CI / Python tests and compilation (push) Successful in 26s
CI / Build and inspect generated packages (push) Successful in 19s
CI / PowerShell tests on Ubuntu (push) Successful in 1m10s
CI / Installed client configuration smoke tests (push) Successful in 50s
CI / Qwen retrieval integration (push) Successful in 14m26s
CI / Capabilities and shell quality (push) Successful in 21s
CI / Bash integration and installation guards (push) Successful in 1m18s
The plan and apply split left exists declared but unused in run_managed_sync
(SC2034), which failed the CI Bash lint.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-01 15:10:11 +02:00
Julian lechnerandClaude Opus 5.5 b110b6d6cd docs(scripts): document provenance checks and config effect tests
CI / CI configuration security checks (push) Successful in 5s
CI / Python tests and compilation (push) Successful in 32s
CI / Build and inspect generated packages (push) Skipped
CI / Installed client configuration smoke tests (push) Skipped
CI / PowerShell tests on Ubuntu (push) Successful in 56s
CI / Qwen retrieval integration (push) Successful in 14m43s
CI / Capabilities and shell quality (push) Failing after 15s
CI / Bash integration and installation guards (push) Skipped
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-01 13:59:13 +02:00
Julian lechnerandClaude Opus 5.5 88f9833455 docs(readme): describe isolated builds and sync rollback
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-01 13:59:13 +02:00
Julian lechnerandClaude Opus 5.5 f43a2df14b test(benchmarks): add C#/ASP.NET and TypeScript tasks
Six tasks with hidden checks: ASP.NET validation and 404 handling, C#
cancellation, and TypeScript overlap, deep merge, and debounce fixes, checked
with dotnet run and node --test.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-01 13:59:12 +02:00
Julian lechnerandClaude Opus 5.5 97879fd6a5 feat(benchmarks): pin models and verify arm provenance
Pin one model and reasoning effort per client for both arms, disable user and
plugin skills in the Codex baseline home, and record what each arm loads in
provenance.json; stop when the arms are not comparable.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-01 13:59:12 +02:00
Julian lechnerandClaude Opus 5.5 9ff0330537 test(config): verify agent limits and permissions take effect
Check that Codex keeps the V1 multi-agent implementation that honors
max_depth, and, with AI_CONFIG_LIVE_TESTS=1, that Claude withholds the Agent
tool from subagents, refuses subagents above the concurrency limit, and
blocks git reset --hard in every shell tool.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-01 13:59:11 +02:00
Julian lechnerandClaude Opus 5.5 dec926fee3 feat(install): roll back interrupted syncs from a journal
Plan each sync before writing, record the plan in .ai-config-transaction.json,
and roll an interrupted destination back from its backups on the next run.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-01 13:59:10 +02:00
Julian lechnerandClaude Opus 5.5 9fc6dc8038 fix(claude): deny destructive commands in both shell tools
Claude offers Bash and PowerShell tools on Windows, but each package denied
git reset --hard, git clean, and recursive deletes only for its own shell. A
live test ran git reset --hard through Bash under the PowerShell package.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-01 13:59:10 +02:00
Julian lechnerandClaude Opus 5.5 cceb9e4839 fix(build): build privately and swap generated/ after validation
Build into a per-run sibling directory and replace generated/ only after
validation, with a lock around the swap, so a failed or parallel build never
leaves generated/ partial.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-01 13:59:10 +02:00
Julian lechnerandClaude Opus 5.5 6d4ac56901 docs(scripts): document the semantic search comparison
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-01 13:27:59 +02:00
Julian lechnerandClaude Opus 5.5 3f554f4351 docs(plugins): describe semantic-search and the Codex sandbox
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-01 13:27:58 +02:00
Julian lechnerandClaude Opus 5.5 2cf7a25baa docs(skills): list the semantic-search skill
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-01 13:27:58 +02:00
Julian lechnerandClaude Opus 5.5 fa593d3b27 feat(benchmarks): accept task name patterns
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-01 13:27:57 +02:00
Julian lechnerandClaude Opus 5.5 e1493d9758 feat(benchmarks): compare sessions with and without semantic search
Add the setup-no-search arm for Claude, generated filler modules, an optional
warm index outside the timing, and a searches count per run.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-01 13:27:57 +02:00
Julian lechnerandClaude Opus 5.5 00a44f50b0 test(benchmarks): add concept-search tasks
Three tasks whose target code shares no vocabulary with the prompt, run in a
repository with generated distractor modules.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-01 13:27:56 +02:00
Julian lechnerandClaude Opus 5.5 a8f6f01f2f docs(rules): point concept questions to semantic-search
Replace the restrictive retrieval paragraph with a short rule: rg for known
names, the semantic-search skill first for concept questions.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-01 13:27:56 +02:00
Julian lechnerandClaude Opus 5.5 587c27c1cd feat(install): install semantic-search only with retrieval
Skip the semantic-search skill while semantic retrieval is disabled and remove
a setup-owned copy when it is turned off.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-01 13:27:55 +02:00
Julian lechnerandClaude Opus 5.5 14e6588d4e feat(skills): add semantic-search skill
Expose the local Qwen search as a skill with an explicit trigger for concept
questions, the command for both shells, result handling, and its limits.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-01 13:27:55 +02:00
Julian lechnerandClaude Opus 5.5 1ad5800833 feat(codex): allow writes to the retrieval data directory
Add the semantic retrieval data directory to
sandbox_workspace_write.writable_roots so Codex can build and refresh the
index without an approval.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-01 13:27:54 +02:00
Julian lechnerandClaude Opus 5.5 14b9185e86 feat(retrieval): create the data directory on install
Sandboxed clients may write only to data/ and cannot create it themselves.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-01 13:27:54 +02:00
Julian lechnerandClaude Opus 5.5 9d922cd678 fix(retrieval): run in-process when pipes are forbidden
The Codex sandbox on Windows denies the pipes that the daemon and worker
process use, so searches waited 120 seconds and then failed. Detect that and
run the search in-process.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-01 13:27:54 +02:00
Julian lechnerandClaude Opus 5.5 739d2f7801 perf(retrieval): use bfloat16 on supporting GPUs
Load both models in bfloat16 when a CUDA GPU supports it and keep float32 on
CPUs. Document the daemon versioning and the indexed file types.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-01 13:13:07 +02:00
Julian lechnerandClaude Opus 5.5 f134c50d39 fix(retrieval): match the Qwen query prompt format
Drop the trailing space after "Query:" as in the model card and include the
prompt in the query cache key.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-01 13:13:06 +02:00
Julian lechnerandClaude Opus 5.5 d60dd10c45 fix(retrieval): end brace-language symbols at top-level braces
Code after a top-level closing brace belonged to the preceding function, for
example shell loops labeled as quote_toml. Attribute it to the module.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-01 13:13:05 +02:00
Julian lechnerandClaude Opus 5.5 e138c0277e feat(retrieval): index markup, style, SQL, and project files
Add HTML, CSS, SCSS, XAML, SQL, XML, project, Razor, Kotlin, Gradle, and
module JavaScript files with SQL and Kotlin symbols, and rebuild the index.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-01 13:13:04 +02:00
Julian lechnerandClaude Opus 5.5 2354ce2c2c fix(retrieval): version the daemon by code hash
Derive the daemon address and start lock from a hash of server.py, so an
updated server never reuses a daemon still running older code.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-01 13:13:03 +02:00
Julian lechnerandClaude Opus 5.5 4e4a10604d fix(retrieval): keep multi-word arguments on Windows
os.execv does not quote arguments on Windows, so the hand-off to the virtual
environment split every multi-word --query and search always failed. Run the
runtime with subprocess on Windows instead.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-01 13:13:02 +02:00
Julian lechnerandClaude Opus 5.5 83e921301b fix(test): start exited process portably in lock test
CI / CI configuration security checks (push) Successful in 4s
CI / Python tests and compilation (push) Successful in 19s
CI / Build and inspect generated packages (push) Successful in 16s
CI / PowerShell tests on Ubuntu (push) Successful in 1m6s
CI / Installed client configuration smoke tests (push) Successful in 44s
CI / Qwen retrieval integration (push) Successful in 14m22s
CI / Capabilities and shell quality (push) Successful in 15s
CI / Bash integration and installation guards (push) Successful in 1m4s
Start-Process -WindowStyle is unavailable in PowerShell on Linux, which broke
the CI PowerShell job. Use ProcessStartInfo with CreateNoWindow instead.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-01 12:49:04 +02:00
Julian lechnerandClaude Opus 5.5 b51e6a4211 docs(scripts): document benchmark and context report
CI / CI configuration security checks (push) Successful in 6s
CI / Python tests and compilation (push) Successful in 19s
CI / Build and inspect generated packages (push) Successful in 15s
CI / PowerShell tests on Ubuntu (push) Failing after 43s
CI / Installed client configuration smoke tests (push) Successful in 59s
CI / Qwen retrieval integration (push) Canceled after 2m1s
CI / Capabilities and shell quality (push) Successful in 14s
CI / Bash integration and installation guards (push) Successful in 1m4s
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-01 12:45:41 +02:00
Julian lechnerandClaude Opus 5.5 89bee27dd2 feat(benchmarks): add setup versus baseline A/B runner
Run tasks with and without the installed setup and compare pass rate, rework,
duration, tokens, cost, tool calls, and workflow checks; exclude runs that end
with a client or API error.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-01 12:45:41 +02:00
Julian lechnerandClaude Opus 5.5 3480072ed7 test(benchmarks): add A/B task fixtures with hidden checks
Ten small Python tasks, each failing on the fixture and passing with a
reference solution, including workflow expectations for a small change, a
bugfix, and a delegable change.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-01 12:45:40 +02:00
Julian lechnerandClaude Opus 5.5 b8fd66ce3b feat(benchmarks): report context the clients actually load
Read Claude /context, /skill-doctor, and its init event, and Codex debug
prompt-input, to list categories, active plugins, and installed skills that
are missing or listed without description context.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-01 12:45:39 +02:00
Julian lechnerandClaude Opus 5.5 e88c1fff89 docs(readme): describe atomic writes and destination locks
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-01 12:45:39 +02:00
Julian lechnerandClaude Opus 5.5 96313f4056 feat(install): lock destinations during sync
Create <destination>/.ai-config.lock exclusively while syncing so parallel
installs or updates fail instead of interleaving writes. A lock left by an
exited process of the same shell on the same host is replaced.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-01 12:45:39 +02:00
Julian lechnerandClaude Opus 5.5 d4143ae2ac fix(install): replace all managed files atomically
Write config.toml, settings.json, the manifest, and every other managed file to
a temporary sibling and rename it over the target, so an interrupted run
cannot leave a partly written file. Previously only SKILL.md was replaced
this way.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-01 12:45:38 +02:00
Julian lechnerandClaude Opus 5.5 3285055d80 fix(validate): check flat Claude rule skills
CI / CI configuration security checks (push) Successful in 5s
CI / Python tests and compilation (push) Successful in 18s
CI / Build and inspect generated packages (push) Successful in 16s
CI / PowerShell tests on Ubuntu (push) Successful in 1m2s
CI / Installed client configuration smoke tests (push) Successful in 34s
CI / Qwen retrieval integration (push) Successful in 14m22s
CI / Capabilities and shell quality (push) Successful in 14s
CI / Bash integration and installation guards (push) Successful in 1m5s
Look for rule skills under skills/rules-*/ and fail when none exist, so a
layout change cannot silently skip their frontmatter validation.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-01 11:13:01 +02:00
Julian lechnerandClaude Opus 5.5 6d53597dbf fix(budget): read flat Claude rule skills
The flat Claude layout moved rule skills to skills/rules-*/, which made the
prompt budget fail to find rules-security.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-01 11:13:00 +02:00
Julian lechnerandClaude Opus 5.5 f83b0add58 docs(skills): describe flat Claude skill layout
CI / CI configuration security checks (push) Successful in 5s
CI / Python tests and compilation (push) Successful in 24s
CI / Build and inspect generated packages (push) Successful in 17s
CI / PowerShell tests on Ubuntu (push) Successful in 54s
CI / Installed client configuration smoke tests (push) Successful in 1m2s
CI / Qwen retrieval integration (push) Canceled after 5m28s
CI / Capabilities and shell quality (push) Successful in 17s
CI / Bash integration and installation guards (push) Failing after 59s
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-01 11:02:07 +02:00
Julian lechnerandClaude Opus 5.5 3203e4ed67 fix(build): generate flat Claude skill directories
Claude discovers only skills/<name>/SKILL.md, so 84 nested skills, including
all rule skills, were invisible. Flatten the categorized catalog for Claude,
keep references, and fail the build on duplicate names or a name that differs
from its directory.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-01 11:02:07 +02:00
Julian lechnerandClaude Opus 5.5 5c1bee043d docs(scripts): document required client mode
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-01 11:02:06 +02:00
Julian lechnerandClaude Opus 5.5 e49dd3f4bc ci: run client behavior smoke tests
Run scripts/tests/test-client-smoke.py in the client-smoke job with required
clients, Python, and Claude sandbox dependencies.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-01 11:02:06 +02:00
Julian lechnerandClaude Opus 5.5 82391bdfbf test(clients): add smoke test timeouts and required-client mode
Read client output on a thread with a deadline so a silent or exited client
fails instead of hanging, and fail on a missing CLI when
AI_CONFIG_REQUIRE_CLIENTS=1.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-01 11:02:05 +02:00
Julian lechnerandClaude Opus 5.5 c14101e60d refactor(skills): move site-architecture catalogs to references
Keep the decision steps in SKILL.md and move catalogs, examples, and
checklists verbatim to references/ to reduce the context cost of loading the
skill.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-01 11:01:55 +02:00
Julian lechnerandClaude Opus 5.5 c8b00584d9 refactor(skills): move copy-editing catalogs to references
Keep the decision steps in SKILL.md and move catalogs, examples, and
checklists verbatim to references/ to reduce the context cost of loading the
skill.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-01 11:01:55 +02:00
Julian lechnerandClaude Opus 5.5 d841ce6ead refactor(skills): move image catalogs to references
Keep the decision steps in SKILL.md and move catalogs, examples, and
checklists verbatim to references/ to reduce the context cost of loading the
skill.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-01 11:01:55 +02:00
Julian lechnerandClaude Opus 5.5 310876a466 refactor(skills): move content-strategy catalogs to references
Keep the decision steps in SKILL.md and move catalogs, examples, and
checklists verbatim to references/ to reduce the context cost of loading the
skill.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-01 11:01:54 +02:00
Julian lechnerandClaude Opus 5.5 4c93437e59 refactor(skills): move marketing-psychology catalogs to references
Keep the decision steps in SKILL.md and move catalogs, examples, and
checklists verbatim to references/ to reduce the context cost of loading the
skill.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-01 11:01:54 +02:00
Julian lechnerandClaude Opus 5.5 569f55dd0d refactor(rules): merge Angular subscription lifetime rules
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-01 11:01:46 +02:00
Julian lechnerandClaude Opus 5.5 e8cdcec629 refactor(rules): deduplicate Angular signal state rules
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-01 11:01:46 +02:00
Julian lechnerandClaude Opus 5.5 85221f6c97 docs(config): document Claude subagent limits
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-01 11:01:45 +02:00
Julian lechnerandClaude Opus 5.5 a30440f55d feat(claude): limit concurrent subagents and spawn depth
Set CLAUDE_CODE_MAX_CONCURRENT_SUBAGENTS=5 and
CLAUDE_CODE_MAX_SUBAGENT_SPAWN_DEPTH=1 so Claude matches the Codex agent
limits and subagents cannot start further subagents.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-01 11:01:45 +02:00
Julian lechnerandClaude Opus 5.5 37d3475b92 docs(scripts): list client smoke test
CI / CI configuration security checks (push) Successful in 5s
CI / Python tests and compilation (push) Successful in 18s
CI / Build and inspect generated packages (push) Successful in 11s
CI / PowerShell tests on Ubuntu (push) Successful in 50s
CI / Installed client configuration smoke tests (push) Successful in 48s
CI / Qwen retrieval integration (push) Successful in 14m55s
CI / Capabilities and shell quality (push) Successful in 14s
CI / Bash integration and installation guards (push) Successful in 58s
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-01 10:23:24 +02:00
Julian lechnerandClaude Opus 5.5 cd2f4fa93e test(clients): add behavioral client smoke tests
Install a generated package into a temporary home with foreign settings, then
ask the real Claude and Codex CLIs which skills, agents, and hooks they
discover. No model request completes. The Claude skill check currently fails
because Claude does not discover nested package skills.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-01 10:23:23 +02:00
Julian lechnerandClaude Opus 5.5 e2394ca1d1 fix(install): keep foreign Claude hooks in mixed groups
Remove only setup-owned hook entries from a hook group and keep foreign
entries with their group options, such as matcher.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-01 10:23:23 +02:00
Julian lechnerandClaude Opus 5.5 857720bcfd fix(install): exchange install option content through UTF-8 files
Windows PowerShell pipes re-encode text by console code page: under code page
65001 a BOM broke the config.toml merge, and otherwise non-ASCII characters
became question marks. Pass managed and merged content through files, and
decode piped input as utf-8-sig.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-01 10:23:14 +02:00
Julian lechnerandClaude Opus 5.5 bed90fee2d docs(rules): align technology comment rules
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-01 10:22:50 +02:00
Julian lechnerandClaude Opus 5.5 996233c663 docs(rules): unify documentation update rule
Update directly affected documentation and comments; add other documentation
only for a concrete need. The implementer and definition of done now defer to
the general rule instead of requiring explicit approval.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-01 10:22:50 +02:00
Julian lechnerandClaude Opus 5.5 f63770efbf docs(config): describe sandbox network and Context7 permissions
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-01 10:22:42 +02:00
Julian lechnerandClaude Opus 5.5 3067d82e1a feat(claude): allow Context7 domain in enabled sandbox
Where the Claude sandbox is enabled, permit network access to
mcp.context7.com only, and validate that exact shape.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-01 10:22:42 +02:00
Julian lechnerandClaude Opus 5.5 d5c29cb1b6 feat(claude): allow Context7 calls through MCPorter
Add a shell-specific permission for `mcporter call context7.*` so Claude can
query Context7 through MCPorter without a permission prompt.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-01 10:22:35 +02:00
Julian lechnerandClaude Opus 5.5 f76e13fc18 feat(codex): allow network access in workspace sandbox
Enable sandbox_workspace_write.network_access so MCPorter calls such as
Context7 run without an approval round trip.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-01 10:22:07 +02:00
Julian lechnerandClaude Opus 5.5 736b1d1d9e docs(skills): note Superpowers ownership of general workflows
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-01 10:22:07 +02:00
Julian lechnerandClaude Opus 5.5 e237d07441 refactor(skills): remove workflows covered by Superpowers
Drop the debugging, implementation-planner, code-review, and
regression-verification skills so Superpowers owns these triggers without
competing descriptions. Focused domain skills remain.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-01 10:21:59 +02:00
Julian lechnerandClaude Opus 5.5 b4aa484f1a docs(config): document unmanaged TOML table retention
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-01 10:21:49 +02:00
Julian lechnerandClaude Opus 5.5 1a6cc4d46f fix(config): preserve unmanaged Codex TOML tables
Keep foreign tables such as mcp_servers and model_providers during config
synchronization instead of dropping them; only setup-owned keys are replaced.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-01 10:21:41 +02:00
Julian lechner 1cba8850f9 docs(scripts): update command and benchmark guidance
CI / Python tests and compilation (push) Successful in 18s
CI / CI configuration security checks (push) Successful in 4s
CI / Build and inspect generated packages (push) Successful in 10s
CI / PowerShell tests on Ubuntu (push) Successful in 51s
CI / Installed client configuration smoke tests (push) Successful in 15s
CI / Qwen retrieval integration (push) Successful in 14m25s
CI / Capabilities and shell quality (push) Successful in 14s
CI / Bash integration and installation guards (push) Successful in 53s
2026-09-30 17:12:12 +02:00
Julian lechner 467a25f002 docs(config): describe current sync behavior 2026-09-30 17:11:51 +02:00
Julian lechner 260256fe6c docs(skills): document reduced catalog and budgets 2026-09-30 17:11:30 +02:00
Julian lechner 831d55b264 fix(doctor): expose skill scan errors 2026-09-30 17:10:30 +02:00
Julian lechner f7eec43122 test(skills): verify reduced catalog handling 2026-09-30 17:10:08 +02:00
Julian lechner 05663197f7 feat(customizations): add removal commands 2026-09-30 17:08:59 +02:00
Julian lechner 29c0e98272 fix(retrieval): normalize vector result IDs 2026-09-30 17:08:22 +02:00
Julian lechner 9bc3f253c1 fix(retrieval): validate owned index data 2026-09-30 17:08:03 +02:00
Julian lechner 8e4aa0523e fix(install): keep skill backups undiscoverable 2026-09-30 17:07:33 +02:00
Julian lechner 0a8a54bf99 feat(rules-java): expand language guidance 2026-09-30 17:07:05 +02:00
Julian lechner 30a6a4e51d chore(skills): prune marketing catalog 2026-09-30 17:06:35 +02:00
Julian lechner 6361e81915 fix(plugins): update installed QMD without reinstalling 2026-09-30 12:44:35 +02:00
Julian lechner 756b8fe59e fix(retrieval): accept generated Python bytecode cache
CI / Python tests and compilation (push) Successful in 25s
CI / CI configuration security checks (push) Successful in 5s
CI / Build and inspect generated packages (push) Successful in 14s
CI / PowerShell tests on Ubuntu (push) Successful in 1m14s
CI / Installed client configuration smoke tests (push) Successful in 14s
CI / Qwen retrieval integration (push) Successful in 14m18s
CI / Capabilities and shell quality (push) Successful in 12s
CI / Bash integration and installation guards (push) Successful in 1m38s
2026-09-30 11:41:45 +02:00
Julian lechner 280292d72e fix(plugins): detect Context7 managed by MCPorter
CI / Python tests and compilation (push) Successful in 22s
CI / CI configuration security checks (push) Successful in 4s
CI / Build and inspect generated packages (push) Successful in 13s
CI / PowerShell tests on Ubuntu (push) Successful in 1m10s
CI / Installed client configuration smoke tests (push) Successful in 13s
CI / Qwen retrieval integration (push) Successful in 14m24s
CI / Capabilities and shell quality (push) Successful in 12s
CI / Bash integration and installation guards (push) Successful in 1m38s
2026-09-30 11:32:27 +02:00
Julian lechner 728d72312f test(packages): count sandbox properties correctly
CI / Python tests and compilation (push) Successful in 22s
CI / CI configuration security checks (push) Successful in 4s
CI / Build and inspect generated packages (push) Successful in 14s
CI / PowerShell tests on Ubuntu (push) Successful in 1m10s
CI / Installed client configuration smoke tests (push) Successful in 14s
CI / Qwen retrieval integration (push) Successful in 14m23s
CI / Capabilities and shell quality (push) Successful in 12s
CI / Bash integration and installation guards (push) Successful in 1m36s
2026-09-30 11:04:22 +02:00
Julian lechner 2d43055a9c test(packages): check Claude sandbox by platform
CI / Python tests and compilation (push) Successful in 22s
CI / CI configuration security checks (push) Successful in 4s
CI / Build and inspect generated packages (push) Successful in 11s
CI / PowerShell tests on Ubuntu (push) Failing after 1m11s
CI / Installed client configuration smoke tests (push) Successful in 28s
CI / Qwen retrieval integration (push) Canceled after 5m19s
CI / Capabilities and shell quality (push) Successful in 12s
CI / Bash integration and installation guards (push) Successful in 1m38s
2026-09-30 10:56:02 +02:00
Julian lechner fec3f75d4c fix(config): drop unmanaged TOML tables
CI / Python tests and compilation (push) Successful in 22s
CI / CI configuration security checks (push) Successful in 4s
CI / Build and inspect generated packages (push) Successful in 14s
CI / PowerShell tests on Ubuntu (push) Failing after 1m11s
CI / Installed client configuration smoke tests (push) Successful in 14s
CI / Qwen retrieval integration (push) Canceled after 7m5s
CI / Capabilities and shell quality (push) Successful in 13s
CI / Bash integration and installation guards (push) Failing after 15s
2026-09-30 10:41:55 +02:00
Julian lechner 6ab92ec30e fix(config): preserve TOML table indentation
CI / Python tests and compilation (push) Successful in 22s
CI / CI configuration security checks (push) Successful in 4s
CI / Build and inspect generated packages (push) Successful in 13s
CI / PowerShell tests on Ubuntu (push) Failing after 55s
CI / Installed client configuration smoke tests (push) Successful in 14s
CI / Qwen retrieval integration (push) Canceled after 6m14s
CI / Capabilities and shell quality (push) Successful in 12s
CI / Bash integration and installation guards (push) Failing after 16s
2026-09-30 10:33:51 +02:00
Julian lechner 1b13bed418 test(retrieval): initialize temporary repositories
CI / Python tests and compilation (push) Successful in 48s
CI / CI configuration security checks (push) Successful in 3s
CI / Build and inspect generated packages (push) Successful in 13s
CI / PowerShell tests on Ubuntu (push) Failing after 55s
CI / Installed client configuration smoke tests (push) Successful in 35s
CI / Qwen retrieval integration (push) Canceled after 6m44s
CI / Capabilities and shell quality (push) Successful in 13s
CI / Bash integration and installation guards (push) Failing after 17s
2026-09-30 10:26:37 +02:00
Julian lechner a67c34f78d fix(retrieval): honor ignore rules and scale search
CI / PowerShell tests on Ubuntu (push) Successful in 12s
CI / Python tests and compilation (push) Failing after 35s
CI / Build and inspect generated packages (push) Skipped
CI / Installed client configuration smoke tests (push) Skipped
CI / Qwen retrieval integration (push) Skipped
CI / CI configuration security checks (push) Successful in 3s
CI / Capabilities and shell quality (push) Successful in 23s
CI / Bash integration and installation guards (push) Skipped
2026-09-30 09:56:57 +02:00
Julian lechner 24f4d8e1e5 feat(prompt-budget): bundle startup context estimates 2026-09-30 09:43:51 +02:00
Julian lechner d71db16198 docs(security): add focused rule index 2026-09-30 09:38:41 +02:00
Julian lechner 066cbb7037 fix(prompt-budget): count all startup skill metadata 2026-09-30 09:38:41 +02:00
Julian lechner 17e8be13b7 fix(update): retain custom config keys 2026-09-30 09:27:48 +02:00
Julian lechner 71daa05071 feat(skills): add marketing skills collection 2026-09-30 09:24:23 +02:00
Julian lechner b3a19860b4 docs(azure-devops): honor explicit write requests 2026-09-30 09:23:52 +02:00
Julian lechner dba4d28403 docs: restrict maintenance work to repository 2026-09-30 09:23:52 +02:00
Julian lechner 5c1795a601 docs(security): define baseline and testing scope 2026-09-30 09:23:52 +02:00
Julian lechner da11841565 fix(doctor): detect underscored placeholders 2026-09-30 09:23:39 +02:00
Julian lechner 060d3724d6 fix(claude): apply shell rules and platform sandbox 2026-09-30 09:23:39 +02:00
Julian lechner 3973ed48f3 fix(update): preserve unmanaged client settings 2026-09-30 09:22:55 +02:00
Julian lechner 097cec41c2 docs(csharp): require null-safe code 2026-09-30 08:39:23 +02:00
Julian lechner 36f58626d8 Normalize doctor.ps1 line endings
CI / Python tests and compilation (push) Successful in 14s
CI / PowerShell tests on Ubuntu (push) Successful in 42s
CI / CI configuration security checks (push) Successful in 4s
CI / Build and inspect generated packages (push) Successful in 10s
CI / Qwen retrieval integration (push) Successful in 14m24s
CI / Installed client configuration smoke tests (push) Successful in 13s
CI / Capabilities and shell quality (push) Successful in 12s
CI / Bash integration and installation guards (push) Successful in 45s
2026-09-28 09:23:55 +02:00
fraujulian e712a75e22 docs(agents): scope task state to long work
CI / Python tests and compilation (push) Successful in 13s
CI / PowerShell tests on Ubuntu (push) Successful in 42s
CI / CI configuration security checks (push) Successful in 4s
CI / Build and inspect generated packages (push) Successful in 9s
CI / Qwen retrieval integration (push) Successful in 14m24s
CI / Installed client configuration smoke tests (push) Successful in 14s
CI / Capabilities and shell quality (push) Successful in 12s
CI / Bash integration and installation guards (push) Successful in 45s
2026-09-25 19:11:51 +02:00
fraujulian 67b5ba5b59 docs(prompt-budget): clarify measured context 2026-09-25 19:11:44 +02:00
fraujulian 3e043da9aa ci: build packages for integration checks 2026-09-25 19:11:36 +02:00
fraujulian 32154e6a89 test(prompt-budget): cover token thresholds 2026-09-25 19:11:28 +02:00
fraujulian 8fc141860f feat(prompt-budget): track context KPIs 2026-09-25 19:11:21 +02:00
fraujulian d9586dca53 docs(scripts): clarify prompt size limits
CI / Python tests and compilation (push) Successful in 13s
CI / PowerShell tests on Ubuntu (push) Successful in 40s
CI / CI configuration security checks (push) Successful in 4s
CI / Build and inspect generated packages (push) Successful in 9s
CI / Qwen retrieval integration (push) Successful in 14m23s
CI / Installed client configuration smoke tests (push) Successful in 23s
CI / Capabilities and shell quality (push) Successful in 11s
CI / Bash integration and installation guards (push) Successful in 43s
2026-09-25 18:16:11 +02:00
fraujulian 2b04fcf7fe test(packages): check current MCP routing rules 2026-09-25 18:16:00 +02:00
fraujulian 4865bea481 docs(git): require git commands for commits and pushes
CI / Python tests and compilation (push) Successful in 13s
CI / PowerShell tests on Ubuntu (push) Failing after 41s
CI / CI configuration security checks (push) Successful in 4s
CI / Build and inspect generated packages (push) Successful in 9s
CI / Installed client configuration smoke tests (push) Canceled after 0s
CI / Qwen retrieval integration (push) Canceled after 2m9s
CI / Capabilities and shell quality (push) Successful in 14s
CI / Bash integration and installation guards (push) Canceled after 0s
2026-09-25 18:04:35 +02:00
fraujulian 1f3ff6576c chore: remove todo ledger 2026-09-25 17:54:15 +02:00
fraujulian e16eeefe3b docs(agents): separate review from verification 2026-09-25 17:53:58 +02:00
fraujulian def30779c8 docs(mcp): clarify native and mcporter routing 2026-09-25 17:53:35 +02:00
fraujulian 0d771c7ee3 chore(prompt-budget): separate soft target from hard limit 2026-09-25 17:52:35 +02:00
fraujulian 4f2688cba2 Merge remote-tracking branch 'origin/main'
CI / Python tests and compilation (push) Successful in 15s
CI / PowerShell tests on Ubuntu (push) Successful in 40s
CI / CI configuration security checks (push) Successful in 4s
CI / Build and inspect generated packages (push) Successful in 9s
CI / Qwen retrieval integration (push) Successful in 14m23s
CI / Installed client configuration smoke tests (push) Successful in 14s
CI / Capabilities and shell quality (push) Successful in 12s
CI / Bash integration and installation guards (push) Successful in 43s
# Conflicts:
#	scripts/lib/plugins.ps1
2026-09-25 11:11:15 +02:00
fraujulian 7558addb79 fix(ci): tolerate missing client CLIs 2026-09-25 11:05:14 +02:00
fraujulian fedbc32e71 fix(ci): tolerate missing client CLIs
CI / Python tests and compilation (push) Canceled after 0s
CI / PowerShell tests on Ubuntu (push) Canceled after 0s
CI / Build and inspect generated packages (push) Canceled after 0s
CI / Installed client configuration smoke tests (push) Canceled after 0s
CI / Qwen retrieval integration (push) Canceled after 0s
CI / Capabilities and shell quality (push) Canceled after 0s
CI / Bash integration and installation guards (push) Canceled after 0s
CI / CI configuration security checks (push) Canceled after 0s
2026-09-25 08:44:08 +00:00
fraujulian 632afdf6b4 fix(ci): prepare summaries and missing clients
CI / Python tests and compilation (push) Successful in 14s
CI / PowerShell tests on Ubuntu (push) Failing after 21s
CI / CI configuration security checks (push) Successful in 3s
CI / Build and inspect generated packages (push) Successful in 9s
CI / Installed client configuration smoke tests (push) Canceled after 0s
CI / Qwen retrieval integration (push) Canceled after 12m46s
CI / Capabilities and shell quality (push) Successful in 12s
CI / Bash integration and installation guards (push) Canceled after 0s
2026-09-25 08:40:12 +00:00
fraujulian cf8e7cfc1b fix(ci): align summary and Bash validation
CI / Python tests and compilation (push) Successful in 13s
CI / PowerShell tests on Ubuntu (push) Failing after 15s
CI / CI configuration security checks (push) Successful in 3s
CI / Build and inspect generated packages (push) Successful in 10s
CI / Qwen retrieval integration (push) Successful in 14m24s
CI / Installed client configuration smoke tests (push) Successful in 42s
CI / Capabilities and shell quality (push) Successful in 14s
CI / Bash integration and installation guards (push) Failing after 34s
2026-09-25 07:21:33 +00:00
fraujulian 6a1730c6ec fix(ci): resolve Linux and summary checks
CI / Python tests and compilation (push) Successful in 14s
CI / PowerShell tests on Ubuntu (push) Failing after 17s
CI / CI configuration security checks (push) Successful in 3s
CI / Build and inspect generated packages (push) Failing after 9s
CI / Installed client configuration smoke tests (push) Skipped
CI / Qwen retrieval integration (push) Successful in 14m48s
CI / Capabilities and shell quality (push) Successful in 13s
CI / Bash integration and installation guards (push) Skipped
2026-09-25 07:10:26 +00:00
fraujulian d5c2ca556b docs(rules): clarify just-in-time loading
CI / Python tests and compilation (push) Failing after 8s
CI / Build and inspect generated packages (push) Skipped
CI / Installed client configuration smoke tests (push) Skipped
CI / Qwen retrieval integration (push) Skipped
CI / PowerShell tests on Ubuntu (push) Failing after 15s
CI / CI configuration security checks (push) Successful in 4s
CI / Capabilities and shell quality (push) Failing after 11s
CI / Bash integration and installation guards (push) Skipped
2026-09-24 22:59:17 +02:00
fraujulian 3fcc2aa709 docs(install): explain saved status line choice 2026-09-24 22:59:17 +02:00
fraujulian ee19c64beb feat(install): configure custom status line 2026-09-24 22:58:56 +02:00
fraujulian 0d034f4299 fix(retrieval): invalidate stale model caches 2026-09-24 22:20:30 +02:00
fraujulian 2efa43365e docs(instructions): condense global rules 2026-09-24 22:20:00 +02:00
fraujulian b54c3d61d0 docs(security): strengthen web guidance 2026-09-24 22:04:13 +02:00
fraujulian c086919866 docs(security): strengthen supply chain guidance 2026-09-24 22:04:01 +02:00
fraujulian 6a513de496 docs(security): strengthen network guidance 2026-09-24 22:03:28 +02:00
fraujulian 0041fbe777 docs(security): strengthen file guidance 2026-09-24 22:03:18 +02:00
fraujulian 2c60db173d docs(security): strengthen data guidance 2026-09-24 22:03:06 +02:00
fraujulian 605d0ef64a docs(security): strengthen crypto guidance 2026-09-24 22:02:41 +02:00
fraujulian a96b198e23 docs(security): strengthen auth guidance 2026-09-24 22:02:23 +02:00
fraujulian e5827e7ddb docs(security): strengthen API guidance 2026-09-24 22:02:12 +02:00
fraujulian 56a71a8f2c docs(security): define authorized testing scope 2026-09-24 22:00:53 +02:00
fraujulian 65f99d398e perf(java): add JVM performance guidance 2026-09-24 22:00:29 +02:00
fraujulian 9bf0d1b1e2 feat(java): add modern Java rules 2026-09-24 21:59:59 +02:00
fraujulian 0bdd5f46b3 refactor(rules): group focused security rules 2026-09-24 21:47:59 +02:00
fraujulian 646e552ff1 refactor(rules): split TypeScript guidance by topic 2026-09-24 21:47:29 +02:00
fraujulian 27db155b85 refactor(rules): split C# guidance by topic 2026-09-24 21:46:50 +02:00
fraujulian d4f45a3320 refactor(rules): move UI principles to topic rule 2026-09-24 21:45:33 +02:00
fraujulian ca9f6296d6 refactor(rules): keep WPF index focused 2026-09-24 21:45:25 +02:00
fraujulian c91505a568 refactor(rules): keep Angular index focused 2026-09-24 21:45:15 +02:00
fraujulian 5c25b4fe5a docs(rules): document focused rule directories 2026-09-24 21:44:29 +02:00
fraujulian bb03528337 refactor(rules): route loading by focused topic 2026-09-24 21:43:06 +02:00
fraujulian ce54b34092 test(rules): verify nested rule packages 2026-09-24 21:42:57 +02:00
fraujulian a7a7c3caba build(rules): generate skills from nested topics 2026-09-24 21:42:49 +02:00
fraujulian 67f7c9041e docs(skills): update skill catalog 2026-09-24 19:12:35 +02:00
fraujulian f87db70f78 docs(skill): clarify work item verification triggers 2026-09-24 19:12:30 +02:00
fraujulian 8ace616ea5 docs(skill): clarify regression verification triggers 2026-09-24 19:12:26 +02:00
fraujulian a8d1ea6554 docs(skill): clarify fact verification triggers 2026-09-24 19:12:20 +02:00
fraujulian 2646bfaa8b docs(skill): clarify WPF review triggers 2026-09-24 19:12:16 +02:00
fraujulian bc0fd83e14 docs(skill): clarify UI UX review triggers 2026-09-24 19:12:11 +02:00
fraujulian 7bac5a75c6 docs(skill): clarify security review triggers 2026-09-24 19:12:07 +02:00
fraujulian f3f02a393a docs(skill): clarify performance review triggers 2026-09-24 19:12:02 +02:00
fraujulian 9996eb64a6 docs(skill): clarify EF Core review triggers 2026-09-24 19:11:56 +02:00
fraujulian 2ded5617af docs(skill): clarify code review triggers 2026-09-24 19:11:52 +02:00
fraujulian 34a65d9019 docs(skill): clarify business review triggers 2026-09-24 19:11:46 +02:00
fraujulian f58cffd4d7 docs(skill): clarify API review triggers 2026-09-24 19:11:38 +02:00
fraujulian 2b6985c37f docs(skill): clarify technical research triggers 2026-09-24 19:11:34 +02:00
fraujulian 28fa850dcc docs(skill): clarify repository research triggers 2026-09-24 19:11:29 +02:00
fraujulian d42a70605d docs(skill): clarify work item skill triggers 2026-09-24 19:11:25 +02:00
fraujulian 2e18a66a77 docs(skill): clarify planning skill triggers 2026-09-24 19:11:21 +02:00
fraujulian e5205316ab docs(skill): clarify impact analysis triggers 2026-09-24 19:11:15 +02:00
fraujulian 3e1db3d6f2 docs(skill): clarify unit test triggers 2026-09-24 19:11:09 +02:00
fraujulian 4d06ceb223 docs(skill): clarify SQL skill triggers 2026-09-24 19:11:04 +02:00
fraujulian 3982f4c430 docs(skill): clarify integration test triggers 2026-09-24 19:11:00 +02:00
fraujulian afb9ea6521 docs(skill): clarify pull request review triggers 2026-09-24 19:10:56 +02:00
fraujulian e8fea95774 docs(skill): clarify debugging triggers 2026-09-24 19:10:47 +02:00
fraujulian e3f4e01fea chore(skill): remove answer-pull-request 2026-09-24 19:10:01 +02:00
fraujulian aeec4d351c refactor(rules): move loading map to global instructions 2026-09-24 18:48:17 +02:00
381 changed files with 15459 additions and 3082 deletions

No files matched your search

+40 -30
View File
@@ -64,24 +64,25 @@ jobs:
timeout-minutes: 20
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- name: Check PowerShell runtime
- name: Install PowerShell runtime
shell: bash
run: |
if command -v pwsh >/dev/null 2>&1; then
echo 'POWERSHELL_AVAILABLE=true' >> "$GITHUB_ENV"
exit 0
fi
if sudo apt-get update && sudo apt-get install --yes --no-install-recommends powershell; then
echo 'POWERSHELL_AVAILABLE=true' >> "$GITHUB_ENV"
else
echo 'POWERSHELL_AVAILABLE=false' >> "$GITHUB_ENV"
echo '::warning::PowerShell is unavailable; PowerShell checks skipped for this runner.'
set -euo pipefail
if ! command -v pwsh >/dev/null 2>&1; then
# Microsoft's signed apt repository; the job fails when PowerShell cannot be installed.
. /etc/os-release
wget -q -O "$RUNNER_TEMP/packages-microsoft-prod.deb" "https://packages.microsoft.com/config/$ID/$VERSION_ID/packages-microsoft-prod.deb"
sudo dpkg -i "$RUNNER_TEMP/packages-microsoft-prod.deb"
sudo apt-get update
sudo apt-get install --yes --no-install-recommends powershell
fi
pwsh -NoLogo -NoProfile -NonInteractive -Command '$PSVersionTable.PSVersion.ToString()'
- name: Run PowerShell tests
shell: bash
run: |
if [ "${POWERSHELL_AVAILABLE:-false}" != true ]; then exit 0; fi
set -euo pipefail
pwsh -NoLogo -NoProfile -NonInteractive -File ./scripts/commands/check-capabilities.ps1
pwsh -NoLogo -NoProfile -NonInteractive -File ./scripts/commands/build.ps1 -Summary
for file in scripts/tests/test-*.ps1; do
echo "==> $file"
pwsh -NoLogo -NoProfile -NonInteractive -File "$file" -Summary
@@ -114,6 +115,10 @@ jobs:
needs: [build]
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- name: Build packages for integration checks
env:
REQUIRE_CODEX_SCHEMA: 'false'
run: bash scripts/commands/build.sh --summary
- name: Run integration tests
run: |
set -euo pipefail
@@ -137,10 +142,13 @@ jobs:
client-smoke:
name: Installed client configuration smoke tests
runs-on: ubuntu-latest
timeout-minutes: 15
timeout-minutes: 20
needs: [build]
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0
with:
python-version: '3.12'
- name: Build packages
run: bash scripts/commands/build.sh --summary
- uses: actions/setup-node@a0853c24544627f65ddf259abe73b1d18a591444 # v22.16.0
@@ -148,6 +156,10 @@ jobs:
node-version: '24'
- name: Install current client CLIs
run: npm install --global @openai/codex @anthropic-ai/claude-code
- name: Install Claude sandbox dependencies
run: |
sudo apt-get update
sudo apt-get install --yes --no-install-recommends bubblewrap socat
- name: Validate current Codex and Claude settings
run: |
set -euo pipefail
@@ -155,30 +167,28 @@ jobs:
cp generated/codex-powershell/config.toml "$schema_home/config.toml"
CODEX_HOME="$schema_home" codex --strict-config --help >/dev/null
claude --settings generated/claude-powershell/settings.json --help >/dev/null
- name: Run client behavior smoke tests
env:
AI_CONFIG_REQUIRE_CLIENTS: '1'
run: timeout 900 python scripts/tests/test-client-smoke.py -v
retrieval:
name: Qwen retrieval integration
qmd:
name: QMD unit tests
runs-on: ubuntu-latest
timeout-minutes: 30
timeout-minutes: 10
needs: [python]
env:
QMD_PACKAGE_DIR: ${{ runner.temp }}/qmd-tests
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0
- uses: actions/setup-node@a0853c24544627f65ddf259abe73b1d18a591444 # v22.16.0
with:
python-version: '3.12'
cache: pip
cache-dependency-path: shared/retrieval/requirements.txt
- name: Install retrieval dependencies
run: python -m pip install -r shared/retrieval/requirements.txt
- uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0
with:
path: .cache/huggingface
key: qwen-retrieval-${{ runner.os }}-${{ hashFiles('shared/retrieval/requirements.txt') }}
- name: Run retrieval tests with real models
env:
QWEN_TEST_MODEL_CACHE: ${{ github.workspace }}/.cache/huggingface
HF_HUB_DISABLE_XET: '1'
run: python scripts/tests/test-retrieval-server.py
node-version: '24'
# CI runs model-free tests only; real-model integration requires a suitable local machine.
- name: Install QMD test dependency
run: npm install --prefix "$QMD_PACKAGE_DIR" --ignore-scripts --no-package-lock --no-audit --no-fund yaml@2.9.0
- name: Run QMD unit tests
run: node --test scripts/tests/test-qmd-lib.mjs scripts/tests/test-qmd-daemon.mjs scripts/tests/test-qmd-search.mjs scripts/tests/test-qmd-warm.mjs scripts/tests/test-qmd-benchmark.mjs
security:
name: CI configuration security checks
+7
View File
@@ -1,4 +1,7 @@
generated/
generated.build-*/
generated.old-*/
generated.lock
.superpowers/
*.log
*.tmp
@@ -12,3 +15,7 @@ credentials.json
secrets.json
!.env.example
.idea
__pycache__/
*.pyc
bin/
obj/
+2 -5
View File
@@ -15,7 +15,7 @@ Keep the architecture as:
- Do not duplicate shared behavior in adapters.
- Treat `generated/` as reproducible build output.
- Maintain equivalent support for both Codex and Claude Code.
- Keep technology-specific rules in separate files under `shared/rules/`.
- Keep each language, framework, and library in its own directory under `shared/rules/`, with an index and focused Markdown rules. Keep security in `shared/rules/security/` and cross-cutting rules such as Git and Microsoft directly under `shared/rules/`.
- Generate those rule files beside `AGENTS.md` and `CLAUDE.md`; load them only when their subject applies.
## Portability
@@ -51,13 +51,10 @@ Write all repository content, generated instructions, scripts, prompts, document
## Installation and security
- Do not install global configuration automatically.
- Perform global installation only after explicit user instruction, using `scripts/commands/install.ps1` so replaced managed files are backed up.
- Keep all task changes inside this repository. Never install, update, or remove configuration, skills, plugins, packages, or settings on the local machine, and never modify files outside the repository. You may change repository code that defines installation behavior, but do not execute it; if a task requires an out-of-repository write, stop and report it.
- Do not add project-specific rules, secrets, credentials, authentication state, or generated runtime state.
## Version control
- Never commit changes unless explicitly instructed.
- Preserve unrelated user changes.
+49 -36
View File
@@ -30,7 +30,7 @@ Bash:
## Quickstart
With the [requirements](#requirements) installed, clone the repository, build it, then install it.
Stop if any command fails. Installation asks for the shell, client, CLI update, Flashbang, Qwen retrieval, and extension choices.
Stop if any command fails. Installation asks for the shell, client, Flashbang, status line, local QMD search models, and extension choices.
PowerShell:
@@ -54,7 +54,7 @@ For an already-installed configuration, use Quickupdate instead.
## Quickupdate
Run these commands from the repository root. Quick reuses the shell, client, CLI update, Flashbang, retrieval, and extension choices from the last
Run these commands from the repository root. Quick reuses the shell, client, Flashbang, status line, retrieval, and extension choices from the last
successful installation or update without opening selection menus. Stop if any command fails.
PowerShell:
@@ -96,11 +96,10 @@ Install and update also rebuild internally; the explicit build above lets you ch
- Separate install, update, and uninstall scripts: install refuses to run against an already-installed destination,
update refuses to run against one that is not installed yet, and uninstall refuses to run against one that was
never installed.
- User-level plugin installation for Ponytail, i-have-adhd, Superpowers, Context7, Caveman, QMD, Humanizer, Impeccable, and
Anthropic Frontend Design, with an interactive extension toggle during both install and update. Only extensions
- User-level extension installation for Ponytail, i-have-adhd, Superpowers, Context7, Caveman, MCPorter,
Humanizer, Impeccable, and Anthropic Frontend Design, with an interactive extension toggle during both install and update. Only extensions
installed and recorded by this setup can be removed through deselection.
- Optional local semantic retrieval for both clients using Qwen3-Embedding-0.6B embeddings and Qwen3-Reranker-0.6B
reranking, disabled by default and removable through the install/update choice.
- Optional local search for both clients through QMD with Qwen3-Embedding-0.6B, Qwen3-Reranker-0.6B, and QMD Query Expansion 1.7B (Yes/No/Auto; Auto benchmarks GPU, then CPU).
## Requirements
@@ -108,11 +107,11 @@ Install and update also rebuild internally; the explicit build above lets you ch
- Bash 4.3 or newer, with standard utilities such as `awk`, `sed`, and `sha256sum`.
- Python 3.11 or newer for configuration validation and task-state hooks/helpers (`python` for PowerShell scripts, `python3` for Bash scripts).
- `jq` for Claude's Bash status line; without it, that status line produces no output.
- Python `venv` and `pip` when the optional semantic retrieval layer is enabled.
- Node.js 22 or newer and `npm` when QMD or MCPorter is selected.
- Node.js 22 or newer and `npm` when local QMD search or MCPorter is selected.
The Bash scripts do not require PowerShell. The PowerShell scripts remain compatible with PowerShell 5.1;
PowerShell 7 can also run them.
Core Bash setup scripts do not require PowerShell. The credential commands use Windows Credential Manager and require
PowerShell, including when invoked through their Bash wrappers. The PowerShell scripts remain compatible with
PowerShell 5.1; PowerShell 7 can also run them.
## Architecture
@@ -128,6 +127,11 @@ shared definitions -> client adapters -> generated packages -> user installation
| [`scripts/`](docs/scripts.md) | Build, installation, update, diagnosis, and validation scripts. |
| `docs/` | Focused documentation about the configuration design. |
Client settings start in `adapters/codex/config/config.toml` and
`adapters/claude/config/settings.json`. Shared Markdown and metadata define behavior;
adapters supply client-specific formats and placeholders resolved during build or installation.
Generated output is not a source to edit.
The build creates:
```text
@@ -142,16 +146,13 @@ generated/
| Document | Contents |
| --- | --- |
| [Architecture](docs/architecture.md) | Shared sources, adapters, generated packages, and installation. |
| [Scripts](docs/scripts.md) | Commands, checks, tests, and internal script layout. |
| [Configuration](docs/configuration.md) | Client settings, permission defaults, status displays, and verification. |
| [Configuration](docs/configuration.md) | Client settings, permissions, status displays, local QMD search, and verification. |
| [Extending the configuration](docs/extending-configuration.md) | Add shared rules, skills, and agents. |
| [Plugins](docs/plugins.md) | Plugin sources, selection, installation, updates, and removal. |
| [Hooks](docs/hooks.md) | Registered events, session-state helpers, notifications, and optional utilities. |
| [Agents](docs/agents.md) | Agent roles and when delegation is useful. |
| [Skills](docs/skills.md) | Skill categories and conditional rule loading. |
| [Codex adapter](adapters/codex/README.md) | Codex-specific configuration files. |
| [Claude Code adapter](adapters/claude/README.md) | Claude-specific configuration files. |
| [Hook package](shared/hooks/README.md) | Overview shipped with the hook scripts. |
| [Repository instructions](AI-Instructions.md) | Rules for maintaining this repository. |
@@ -171,7 +172,9 @@ Bash:
Rebuild when shared definitions, adapters, or generation logic change. Choose other verification according to the
change's risk; documentation-only edits do not require a build. Building writes reproducible packages below
`generated/` and may use temporary validation files; it does not install global user configuration.
`generated/` and may use temporary validation files; it does not install global user configuration. Each build writes
into its own `generated.build-*` directory and replaces `generated/` only after validation, so a failed or parallel
build never leaves it partial.
## Installation Script
@@ -214,23 +217,27 @@ and replaced, with a warning. Untracked files outside package target paths are l
Previously managed files no longer shipped are backed up and removed if unchanged. If locally modified, they are
backed up and retained with a warning. Backups are stored under `backups/<timestamp>/` in each destination.
Local Codex `model`, `model_reasoning_effort`, `plugins`, and `marketplaces` settings are preserved when syncing `config.toml`;
other local settings are not generally merged. Dry runs still rebuild `generated/`, but do not modify installation destinations.
Codex skill backups use `.agents/.ai-config-skill-backups/` instead, so Codex does not discover backup copies as skills.
Existing `.agents/skills/backups/` content is moved there on the next install, update, or uninstall.
Codex `config.toml` synchronization merges setup-owned keys while retaining other root keys, extra fields in managed
tables, plugin and marketplace tables, other unmanaged tables, and unowned array tables. The previous
file is backed up when content changes. Claude `settings.json` synchronization retains unrelated settings and hooks.
Every managed file, including `config.toml`, `settings.json`, and the manifest, is written to a temporary sibling
file and then renamed over the target, so an interrupted run never leaves a partly written file. Each destination is
locked through `.ai-config.lock` while it syncs; a parallel install or update fails instead of interleaving writes.
A lock left by an exited process of the same shell on the same host is replaced automatically.
Before its first write, each sync records its planned changes in `.ai-config-transaction.json`; if a run is interrupted,
the next install or update first rolls that destination back from the backups (`ROLLBACK <destination> <stamp>`).
Dry runs still rebuild `generated/`, but do not modify installation destinations.
Selecting Codex also installs shared skills to `.agents/skills`. An interactive extension list includes plugins and
Codex skills; unchecked extensions are skipped on installation. Normal runs also ask whether to update
the selected client CLIs, enable Flashbang, and enable Qwen3 semantic retrieval. These choices are saved for Quickupdate.
Disabling retrieval on a later update removes its setup-owned runtime and index. Dry runs preview
changes without updating CLIs, extensions, or retrieval. See [Plugins](docs/plugins.md) for client-specific behavior.
Install also always asks `Uninstall Codex/Claude/Both and reinstall via npm?` (default no), scoped to whatever client
was selected. This choice is independent of the "update selected agent CLIs" choice above, is never saved, and is not
asked again by Quickupdate or by the update script. Answering yes uninstalls and reinstalls, per selected client, the
matching CLI (`@openai/codex` for Codex, `@anthropic-ai/claude-code` for Claude) through `npm uninstall -g`
followed by `npm install -g <package>@latest`, when that CLI is currently found as a global npm package. When it is
not (for example, installed through a native installer or another package manager), that prior installation is left
in place with a warning, and only a fresh `npm install -g` is run alongside it. Codex is skipped with a warning while
`codex.exe` is running. A dry run never asks this question and never previews it, since the choice is not persisted.
Codex skills; unchecked extensions are skipped on installation. Normal install and update ask whether to enable
Flashbang, apply the custom status line, and enable local QMD search. Choices are saved for Quickupdate.
The shared skill catalog includes development skills and focused writing, image, site structure, psychology, and
conversion skills. All retained skills are included in both generated clients; installation includes `semantic-search` only when local QMD search is enabled.
The status line defaults to enabled to preserve existing behavior. Disabling it removes the custom client setting and,
for Claude, the setup-owned status line script. Disabling local QMD search removes its setup-owned package, models, and repository collections once no client still uses it. See [Local QMD search](docs/configuration.md#local-qmd-search) for storage and removal details.
Dry runs preview changes without updating extensions or retrieval. See [Plugins](docs/plugins.md) for client-specific behavior.
## Update Script
@@ -249,14 +256,14 @@ Bash:
```
It accepts the same `-DryRun`/`--dry-run`, `-Client`/`--client`, and `-Shell`/`--shell` parameters as the
installer, re-syncs every managed file, and lets you revise the CLI update, Flashbang, retrieval, and extension choices.
installer, re-syncs every managed file, and lets you revise the status line, Flashbang, retrieval, and extension choices.
Selected extensions are installed or updated. Deselection removes only extensions recorded as installed by this
setup; pre-existing or manually installed extensions are retained. Quickupdate reuses the saved choices.
## Uninstall Script
Remove everything this setup previously installed for the selected client(s): managed files tracked in each
destination's manifest, extensions and skills recorded in the extension ledger, an enabled semantic retrieval setup,
destination's manifest, extensions and skills recorded in the extension ledger, an enabled local QMD search setup,
and the saved Quickupdate selection (once no destination remains installed for any client).
PowerShell:
@@ -278,11 +285,12 @@ touching anything, unless `-Force`/`--force` is passed; running without a termin
fails instead of hanging. Removal reuses the same manifest-sync logic as install and update: every managed file is
backed up under `backups/<timestamp>/` before removal, and a file changed locally since the last install/update is
backed up but left in place with a warning instead of being deleted. Files this setup never installed are never
touched. A destination directory is only deleted once it is fully empty; backups already on disk are always kept.
touched. Codex skill backups are kept under `.agents/.ai-config-skill-backups/`. A destination directory is only
deleted once it is fully empty; backups already on disk are always kept.
Extensions and skills recorded in the ledger are removed the same way `update` removes a deselected extension:
pre-existing or manually installed ones outside the ledger are left alone, and a skill file modified since it was
installed is kept with a warning. An enabled semantic retrieval setup is disabled and its setup-owned runtime and
index removed for the selected client(s). The saved Quickupdate selection (`~/.my-ai-configuration/selection.json`)
installed is kept with a warning. Local QMD search is disabled for the selected client(s). Its shared runtime,
owned models, and recorded repository collections are removed only when no client still uses it; the shared QMD database and foreign collections are retained. The saved Quickupdate selection (`~/.my-ai-configuration/selection.json`)
is only removed once uninstalling leaves no client installed at all, so uninstalling just one client out of a
`Both` installation keeps the saved choices for the client that remains.
@@ -293,7 +301,12 @@ keep outside this setup's ledger, or files this setup never installed.
Codex and Claude Code receive the same shared rules, skills, agents, hooks, and status data. Codex loads applicable rules from generated files, while Claude Code exposes technology- and situation-specific rules as generated skills.
The default configuration keeps writes workspace-scoped and enables automatic review for eligible escalation requests. Both clients include the same logical agent roles and compact status displays. See [Configuration](docs/configuration.md) for settings, permissions, and limitations.
Codex defaults to full access under the account that launches it, with unrestricted command network access.
Launch Codex as the repository owner; Codex does not switch to that owner automatically. Full access removes
Codex's filesystem sandbox boundaries. Eligible approval requests still use automatic review. Claude uses
automatic permissions and enables its sandbox where the platform supports it; explicit deny rules still apply where it
does not. Both clients include the same logical agent roles and compact status displays. See
[Configuration](docs/configuration.md) for settings, permissions, and limitations.
## Support
-39
View File
@@ -1,39 +0,0 @@
# TODO
## Data loss and security
- [x] Validate every path read from `.ai-config-manifest.tsv` and reject links before backup, overwrite, or removal. Both manifest writers join unchecked recorded paths to the destination; a `../` entry or linked target can reach files outside the managed directory. (`scripts/lib/manifest.ps1:20`, `scripts/lib/manifest.ps1:136`, `scripts/lib/manifest.sh:20`, `scripts/lib/manifest.sh:170`)
- [x] Keep an installed semantic retrieval runtime when an `auto` benchmark says no. `benchmark()` deletes the whole runtime and ownership state even when `state['clients']` still contains active clients. (`scripts/lib/semantic-retrieval.py:117`, `scripts/lib/semantic-retrieval.py:142`)
- [x] Check semantic retrieval ownership and links before copying or deleting its directory. An existing owned runtime's source files are overwritten without comparing recorded hashes; a replaced target symlink is followed on enable, and disabling the last client removes foreign files inside the runtime. (`scripts/lib/semantic-retrieval.py:82`, `scripts/lib/semantic-retrieval.py:100`)
- [x] Preserve pre-existing MCPorter server entries. `ensure_mcporter()` adds a server and claims ownership without checking existing configuration; if the add succeeds for an existing name, a later removal deletes that user's entry. (`scripts/lib/managed-extensions.py:395`, `scripts/lib/managed-extensions.py:263`)
- [x] Preserve pre-existing global CLI packages. `ensure_cli()` and `ensure_qmd()` install and claim npm packages without checking whether they were already installed; later removal can uninstall a user's package. (`scripts/lib/managed-extensions.py:342`, `scripts/lib/managed-extensions.py:378`)
- [x] Fetch skill archives by an immutable commit and record that same commit. The archive uses GitHub `HEAD`, while `resolvedRevision` comes from a separate later request, so the recorded revision may not identify the installed payload. (`scripts/lib/managed-extensions.py:94`, `scripts/lib/managed-extensions.py:140`, `scripts/lib/managed-extensions.py:409`)
- [x] Protect the semantic retrieval daemon's IPC protocol. It uses a hardcoded authentication key and `multiprocessing.connection.recv()`, which deserializes messages; a process that can reach its socket or pipe can submit arbitrary roots and potentially crafted objects. Use a private per-install credential and a non-pickle wire format, or restrict the endpoint to the current user. (`shared/retrieval/server.py:47`, `shared/retrieval/server.py:306`, `shared/retrieval/server.py:314`)
- [x] Write semantic retrieval ownership state atomically. `save_state()` replaces the JSON with a direct write, unlike the extension and selection ledgers; interruption can leave it unreadable and block later reconciliation. (`scripts/lib/semantic-retrieval.py:63`)
## Menus and reconciliation
- [x] Build update-menu checks per client when `Both` is selected. Both menus inspect Claude's installed plugins for every entry, so a Codex resource can start unchecked and the combined sync can remove it. (`scripts/lib/plugins.ps1:98`, `scripts/lib/plugins.sh:108`)
- [x] Keep shared MCPorter servers until neither client needs them. Reconciliation processes `shared` records even when only one client is selected; uninstalling that client with an empty selection removes servers still used by the other. (`scripts/lib/managed-extensions.py:463`, `scripts/commands/uninstall.ps1:59`, `scripts/commands/uninstall.sh:77`)
- [x] Manage global packages once across clients. With `--client both`, MCPorter is installed and recorded twice; QMD's global package can be removed during a Codex-only deselection while Claude still uses its plugin. (`scripts/lib/managed-extensions.py:342`, `scripts/lib/managed-extensions.py:378`, `scripts/lib/managed-extensions.py:463`)
- [x] Fix Bash `auto` semantic retrieval selection. Both `test_semantic_retrieval_device()` and its caller read `$?` after a completed `if`, losing the benchmark's exit code; an unsuitable device produces an empty choice instead of `false`. (`scripts/lib/semantic-retrieval.sh:13`, `scripts/lib/install-options.sh:52`)
- [x] Make ordinary update dry-runs use the saved/current selection. Both menus bypass selection in dry-run and select every manifest entry, so the preview can diverge from the real update. (`scripts/lib/plugins.ps1:91`, `scripts/lib/plugins.sh:97`)
- [x] Reconcile resources whose ownership record remains but whose installation was removed manually. `ensure_cli()` and `ensure_mcporter()` return early from a ledger record without checking the actual CLI or server; normal sync cannot restore the missing resource. (`scripts/lib/managed-extensions.py:342`, `scripts/lib/managed-extensions.py:395`)
- [x] Update owned MCPorter itself on `--update`. `ensure_cli()` returns whenever its ledger record exists, so a selected MCPorter package never receives the requested update. (`scripts/lib/managed-extensions.py:342`)
- [x] Keep terminal newlines in Bash-managed files that need substitution. Command substitution strips trailing newlines before Bash hashes and writes the content, while PowerShell retains them; switching installers causes needless file changes and backups. (`scripts/lib/manifest.sh:70`, `scripts/lib/manifest.ps1:75`)
- [x] Parse the Bash plugin inventory as JSON and stop when listing fails. `plugin_installed()` searches for one exact spacing pattern and suppresses CLI errors; a minified response or listing failure marks installed plugins unchecked, allowing an update to remove owned plugins. PowerShell parses JSON and fails on a CLI error. (`scripts/lib/plugins.sh:4`, `scripts/lib/plugins.ps1:36`)
- [x] Serialize Bash manifest entries without shell word splitting. `write_managed_manifest()` loops over command substitution; a managed filename containing spaces becomes multiple invalid entries and can no longer be reconciled correctly. (`scripts/lib/manifest.sh:47`)
- [x] Allow uninstall to reconcile owned extensions when file manifests are missing. Both uninstall commands stop with “Not installed” based only on destination manifests, even if `extensions.json` still owns plugins, skills, or MCP servers. (`scripts/commands/uninstall.ps1:21`, `scripts/commands/uninstall.sh:34`)
## Rules, checks, and documentation
- [x] Make `jq` conditional in capability checks. Both checks fail when it is absent, although the runtime doctor only warns and the requirement is limited to Claude's Bash status line. (`scripts/commands/check-capabilities.ps1:12`, `scripts/commands/check-capabilities.sh:19`, `README.md:110`)
- [x] Review the global MCPorter-only rule's failure behavior. It prohibits all direct MCP use and requires stopping when MCPorter is unavailable, even for a user-authorized native connection; decide whether this restriction should be scoped to managed servers. (`shared/global-instructions.md:7`)
- [x] Align Context7 selection with the MCPorter-only rule. If Context7 is selected without MCPorter, reconciliation installs its native client plugin even though the generated instructions forbid using native MCP connections. Either require MCPorter for this entry or change the rule and menu together. (`scripts/lib/managed-extensions.py:465`, `adapters/plugins.tsv:5`, `shared/global-instructions.md:7`)
- [x] Clarify the decision rule for minor reversible UI choices. Its broad instruction to ask when UI/UX behavior is open to interpretation can block routine choices that `general.md` says to make independently unless materially ambiguous. (`shared/rules/decision-rule.md:6`, `shared/rules/general.md:5`)
- [x] Review the permanent-prompt budget thresholds. Both baselines and absolute limits are 6000 bytes, so the advertised 15% relative allowance can never be used; even a small increase past 6000 fails. Decide whether the hard cap or the relative allowance is intended. (`adapters/prompt-budget-baseline.json:1`, `adapters/prompt-budget-baseline.tsv:2`, `scripts/commands/prompt-budget.ps1:26`, `scripts/commands/prompt-budget.sh:20`)
- [x] Correct QMD documentation. It says Codex registers `qmd mcp` and deselection leaves the global executable, while the manager does not register that MCP server and removes owned QMD npm packages. (`docs/plugins.md:17`, `scripts/lib/managed-extensions.py:378`)
- [x] Include source/script changes in Bash repository-context invalidation. Its cache key hashes only `AI-Instructions.md` and `adapters/`, while the PowerShell variant also hashes source scripts; Bash can keep stale context after an uncommitted script or rule edit. (`scripts/commands/repository-context.sh:7`, `scripts/commands/repository-context.ps1:9`)
- [x] Correct the optional command-safety utility description or add the missing Bash check. Documentation says both variants check outside-workspace paths, but only the PowerShell variant attempts that check. The utility is currently unregistered. (`docs/hooks.md:17`, `shared/hooks/scripts/validate-command-safety.sh:4`, `shared/hooks/scripts/Validate-CommandSafety.ps1:4`)
- [x] Align doctor checks across shells. PowerShell checks whether Codex and Claude Stop hooks are registered; Bash omits this check, so the same installation can produce different diagnostics. (`scripts/commands/doctor.ps1:87`, `scripts/commands/doctor.sh:98`)
- [x] Update the documented Claude status-line example to include the `Review` field printed by both implementations. (`docs/configuration.md:24`, `shared/statusline/statusline.ps1:40`, `shared/statusline/statusline.sh:70`)
-3
View File
@@ -1,3 +0,0 @@
# Claude Code adapter
Claude Code uses global `CLAUDE.md`, `settings.json`, skills, and agents under the user profile. This adapter supplies client metadata; semantic content remains in `shared/`.
+2 -2
View File
@@ -1,6 +1,6 @@
role tools
architect Read,Grep,Glob,WebFetch,WebSearch
researcher Read,Grep,Glob,WebFetch,WebSearch
architect Read,Grep,Glob,WebFetch,WebSearch,__SHELL__
researcher Read,Grep,Glob,WebFetch,WebSearch,__SHELL__
reviewer Read,Grep,Glob,__SHELL__
verifier Read,Grep,Glob,__SHELL__
implementer Read,Grep,Glob,Edit,Write,__SHELL__
1 role tools
2 architect Read,Grep,Glob,WebFetch,WebSearch Read,Grep,Glob,WebFetch,WebSearch,__SHELL__
3 researcher Read,Grep,Glob,WebFetch,WebSearch Read,Grep,Glob,WebFetch,WebSearch,__SHELL__
4 reviewer Read,Grep,Glob,__SHELL__
5 verifier Read,Grep,Glob,__SHELL__
6 implementer Read,Grep,Glob,Edit,Write,__SHELL__
+9 -11
View File
@@ -1,19 +1,14 @@
{
"permissions": {
"defaultMode": "auto",
"allow": [
"Agent"
],
"deny": [
"Bash(git reset --hard*)",
"Bash(git clean*)",
"Bash(rm -rf*)",
"Bash(Remove-Item -Recurse*)"
]
"allow": __CLAUDE_ALLOW_RULES__,
"deny": __CLAUDE_DENY_RULES__
},
"sandbox": __CLAUDE_SANDBOX__,
"env": {
"CLAUDE_CODE_MAX_TOOL_USE_CONCURRENCY": "__CLAUDE_CODE_MAX_TOOL_USE_CONCURRENCY__"
"CLAUDE_CODE_MAX_TOOL_USE_CONCURRENCY": "__CLAUDE_CODE_MAX_TOOL_USE_CONCURRENCY__",
"CLAUDE_CODE_MAX_CONCURRENT_SUBAGENTS": "5",
"CLAUDE_CODE_MAX_SUBAGENT_SPAWN_DEPTH": "1"
},
"statusLine": {
"type": "command",
@@ -21,7 +16,10 @@
},
"hooks": {
"PreCompact": [{"hooks": [{"type": "command", "command": "__HOOK_COMMAND__ \"__AI_CONFIG_ROOT__/hooks/scripts/__COMPACT_SCRIPT__\"", "timeout": 4}]}],
"SessionStart": [{"hooks": [{"type": "command", "command": "__HOOK_COMMAND__ \"__AI_CONFIG_ROOT__/hooks/scripts/__SESSION_POINTER_SCRIPT__\"", "timeout": 4}]}],
"SessionStart": [
{"hooks": [{"type": "command", "command": "__HOOK_COMMAND__ \"__AI_CONFIG_ROOT__/hooks/scripts/__SESSION_POINTER_SCRIPT__\"", "timeout": 4}]},
{"hooks": [{"type": "command", "command": "__HOOK_COMMAND__ \"__AI_CONFIG_ROOT__/hooks/scripts/__QMD_WARM_SCRIPT__\"", "timeout": 4}]}
],
"Stop": [
{
"hooks": [
+1 -1
View File
@@ -1 +1 @@
Read skills/rules/rules-orchestration/SKILL.md from your installed configuration before acting as a subagent.
Read skills/rules-orchestration/SKILL.md from your installed configuration before acting as a subagent.
-3
View File
@@ -1,3 +0,0 @@
# Codex adapter
Codex uses global `AGENTS.md`, `config.toml`, skills, and agent configuration under the user profile. This adapter supplies client metadata; semantic content remains in `shared/`.
+10 -5
View File
@@ -1,12 +1,9 @@
approval_policy = "on-request"
approvals_reviewer = "auto_review"
sandbox_mode = "workspace-write"
[windows]
sandbox = "unelevated"
sandbox_mode = "danger-full-access"
[tui]
status_line = ["model", "reasoning", "approval-mode", "project-name", "git-branch", "context-window-size", "context-used", "used-tokens"]
status_line = ["model", "reasoning", "fast-mode", "approval-mode", "five-hour-limit", "weekly-limit", "project-name", "git-branch", "context-window-size", "context-used", "used-tokens"]
[agents]
enabled = true
@@ -15,6 +12,7 @@ max_depth = 1
[features]
hooks = true
api_key_model_discovery = true
[[hooks.Stop]]
[[hooks.Stop.hooks]]
@@ -22,3 +20,10 @@ type = "command"
command = '__HOOK_COMMAND__ "__AI_CONFIG_ROOT__/hooks/__HOOK_SCRIPT__"'
command_windows = '__POWERSHELL_HOOK_COMMAND__ "__AI_CONFIG_ROOT__/hooks/__POWERSHELL_HOOK_SCRIPT__"'
timeout = 8
[[hooks.SessionStart]]
[[hooks.SessionStart.hooks]]
type = "command"
command = '__HOOK_COMMAND__ "__AI_CONFIG_ROOT__/hooks/scripts/__QMD_WARM_SCRIPT__"'
command_windows = '__POWERSHELL_HOOK_COMMAND__ "__AI_CONFIG_ROOT__/hooks/scripts/__QMD_WARM_SCRIPT__"'
timeout = 4
-1
View File
@@ -4,7 +4,6 @@ i-have-adhd ayghri/i-have-adhd i-have-adhd@i-have-adhd ayghri/i-have-adhd i-have
Superpowers anthropics/claude-plugins-official superpowers@claude-plugins-official openai-curated-remote superpowers@openai-curated-remote plugin - -
Context7 upstash/context7 context7@context7-marketplace upstash/context7 context7@context7-marketplace plugin - - context7 https://mcp.context7.com/mcp
Caveman JuliusBrussee/caveman caveman@caveman thinkhome-org/caveman-codex caveman@thinkhome-caveman plugin - -
QMD tobi/qmd qmd@qmd - - qmd @tobilu/qmd qmd
MCPorter - mcporter - mcporter cli mcporter -
Humanizer blader/humanizer humanizer@humanizer - - skill blader/humanizer humanizer
Impeccable pbakaus/impeccable impeccable@impeccable pbakaus/impeccable impeccable skill pbakaus/impeccable impeccable
1 name claude_marketplace claude_plugin codex_marketplace codex_plugin codex_method codex_source codex_skill mcporter_name mcporter_url
4 Superpowers anthropics/claude-plugins-official superpowers@claude-plugins-official openai-curated-remote superpowers@openai-curated-remote plugin - -
5 Context7 upstash/context7 context7@context7-marketplace upstash/context7 context7@context7-marketplace plugin - - context7 https://mcp.context7.com/mcp
6 Caveman JuliusBrussee/caveman caveman@caveman thinkhome-org/caveman-codex caveman@thinkhome-caveman plugin - -
QMD tobi/qmd qmd@qmd - - qmd @tobilu/qmd qmd
7 MCPorter - mcporter - mcporter cli mcporter -
8 Humanizer blader/humanizer humanizer@humanizer - - skill blader/humanizer humanizer
9 Impeccable pbakaus/impeccable impeccable@impeccable pbakaus/impeccable impeccable skill pbakaus/impeccable impeccable
+31 -1
View File
@@ -1 +1,31 @@
{"Claude permanent context":6000,"Codex permanent context":6000,"Claude permanent context absolute limit":6900,"Codex permanent context absolute limit":6900}
{
"regression_percent": 10,
"permanent_context_soft_target_tokens": 10000,
"permanent_context_hard_limit_tokens": 15000,
"metrics": {
"permanent_context_tokens": {
"claude": 5451,
"codex": 3767
},
"instruction_tokens": {
"claude": 1485,
"codex": 1485
},
"skill_metadata_tokens": {
"claude": 3163,
"codex": 1554
},
"auto_loaded_rule_tokens": {
"claude": 678,
"codex": 678
},
"rule_catalog_tokens": {
"claude": 28818,
"codex": 8510
},
"agent_metadata_tokens": {
"claude": 204,
"codex": 124
}
}
}
+13 -2
View File
@@ -1,2 +1,13 @@
Claude 6000 6900
Codex 6000 6900
metric client baseline_tokens
permanent_context_tokens claude 5451
permanent_context_tokens codex 3767
instruction_tokens claude 1485
instruction_tokens codex 1485
skill_metadata_tokens claude 3163
skill_metadata_tokens codex 1554
auto_loaded_rule_tokens claude 678
auto_loaded_rule_tokens codex 678
rule_catalog_tokens claude 28818
rule_catalog_tokens codex 8510
agent_metadata_tokens claude 204
agent_metadata_tokens codex 124
1 Claude metric 6000 client 6900 baseline_tokens
2 Codex permanent_context_tokens 6000 claude 6900 5451
3 permanent_context_tokens codex 3767
4 instruction_tokens claude 1485
5 instruction_tokens codex 1485
6 skill_metadata_tokens claude 3163
7 skill_metadata_tokens codex 1554
8 auto_loaded_rule_tokens claude 678
9 auto_loaded_rule_tokens codex 678
10 rule_catalog_tokens claude 28818
11 rule_catalog_tokens codex 8510
12 agent_metadata_tokens claude 204
13 agent_metadata_tokens codex 124
-21
View File
@@ -1,21 +0,0 @@
rule_file skill_name trigger
angular rules-angular Angular component, template, or RxJS/signal work
csharp.md rules-csharp C# or .NET implementation, review, or refactoring work
decision-rule.md rules-decision-rule unresolved requirements, ambiguous behavior, or a meaningful technical choice
definition-of-done.md rules-definition-of-done validating that a task is complete or ready for review
git.md rules-git Git operations such as commits, branches, or merges
microsoft.md rules-microsoft Microsoft 365, Azure DevOps, or Teams operations
orchestration.md rules-orchestration delegation, subagent work, or long-running task state
refactoring.md rules-refactoring refactoring existing code without changing behavior
security.md rules-security any software development task: implementing, modifying, debugging, reviewing, testing, or configuring code, scripts, hooks, or infrastructure
security-auth.md rules-security-auth authentication, authorization, sessions, tokens, permissions, or tenant-boundary work
security-web.md rules-security-web web, browser, frontend, cookie, redirect, or XSS/CSRF work
security-api.md rules-security-api HTTP API, request handling, serialization, or endpoint work
security-data.md rules-security-data database, query, persistence, sensitive-data, or multi-tenant work
security-files.md rules-security-files file, upload, archive, path, process, IPC, or deserialization work
security-network.md rules-security-network network, URL fetch, proxy, outbound request, TLS, or SSRF work
security-crypto.md rules-security-crypto cryptography, secrets, credentials, key, or token work
security-supply-chain.md rules-security-supply-chain dependency, package, plugin, build, deployment, or CI supply-chain work
typescript.md rules-typescript TypeScript or modern ECMAScript implementation work
ui-ux rules-ui-ux UI or UX design and interaction decisions
wpf rules-wpf WPF, XAML, or MVVM desktop UI work
1 rule_file skill_name trigger
2 angular rules-angular Angular component, template, or RxJS/signal work
3 csharp.md rules-csharp C# or .NET implementation, review, or refactoring work
4 decision-rule.md rules-decision-rule unresolved requirements, ambiguous behavior, or a meaningful technical choice
5 definition-of-done.md rules-definition-of-done validating that a task is complete or ready for review
6 git.md rules-git Git operations such as commits, branches, or merges
7 microsoft.md rules-microsoft Microsoft 365, Azure DevOps, or Teams operations
8 orchestration.md rules-orchestration delegation, subagent work, or long-running task state
9 refactoring.md rules-refactoring refactoring existing code without changing behavior
10 security.md rules-security any software development task: implementing, modifying, debugging, reviewing, testing, or configuring code, scripts, hooks, or infrastructure
11 security-auth.md rules-security-auth authentication, authorization, sessions, tokens, permissions, or tenant-boundary work
12 security-web.md rules-security-web web, browser, frontend, cookie, redirect, or XSS/CSRF work
13 security-api.md rules-security-api HTTP API, request handling, serialization, or endpoint work
14 security-data.md rules-security-data database, query, persistence, sensitive-data, or multi-tenant work
15 security-files.md rules-security-files file, upload, archive, path, process, IPC, or deserialization work
16 security-network.md rules-security-network network, URL fetch, proxy, outbound request, TLS, or SSRF work
17 security-crypto.md rules-security-crypto cryptography, secrets, credentials, key, or token work
18 security-supply-chain.md rules-security-supply-chain dependency, package, plugin, build, deployment, or CI supply-chain work
19 typescript.md rules-typescript TypeScript or modern ECMAScript implementation work
20 ui-ux rules-ui-ux UI or UX design and interaction decisions
21 wpf rules-wpf WPF, XAML, or MVVM desktop UI work
+12 -6
View File
@@ -2,14 +2,20 @@
The five shared agents are logical roles, not mandatory steps.
- `implementer` executes the smallest complete engineering change and performs self-review.
- `researcher` investigates code, patterns, evidence, alternatives, and unknowns without modifying implementation code by default.
- `architect` evaluates technical boundaries, dependencies, interfaces, constraints, and design options.
- `verifier` supplies execution evidence from relevant tests, builds, checks, generated output, and behavior reproduction. It does not repeat a general architecture review.
- `reviewer` starts with the actual diff and changed symbols, then examines necessary callers, dependencies, tests, and contracts for analytical correctness. It does not automatically rerun the test suite.
- `implementer` implements scoped features and fixes with proportionate tests and self-review.
- `researcher` answers questions about repository behavior, external documentation, and unknowns with source evidence, without modifying implementation code by default.
- `architect` compares design options and recommends technical boundaries and interfaces before implementation; implementation changes require an explicit assignment.
- `verifier` supplies execution evidence from relevant tests, builds, checks, generated output, and behavior reproduction. It inspects implementation only to choose checks and does not review the diff for general correctness.
- `reviewer` starts with the actual diff and changed symbols, then examines necessary callers, dependencies, tests, and contracts for analytical correctness. It does not run tests, builds, or runtime checks; it reports missing execution evidence.
Use only the roles that are likely to improve the outcome. Choose `researcher`, `reviewer`, and `verifier` based on the task's uncertainty, complexity, risk, blast radius, and verification value; none runs automatically. The agent may make evidence-based, reversible technical decisions. Ask the user when technical choices remain materially uncertain or when business behavior, user-visible behavior, UI, UX, APIs, database models, configuration formats, compatibility behavior, or other high-impact decisions are ambiguous or open to interpretation.
## Research tools
Claude's [capability manifest](../adapters/claude/capabilities.tsv) gives `architect` and `researcher` file inspection, web research, and the package's shell tool (`PowerShell` or `Bash`). Shell access supports mandatory semantic search and Context7 research through MCPorter. Their role instructions scope shell use to inspection and research; this is an instruction-level boundary, not a read-only shell sandbox.
The `reviewer` may inspect Git diffs and run required research commands through its shell tool. Tests, builds, and behavior reproduction belong to the `verifier` or parent. Missing execution evidence remains an explicit review gap. Codex receives the same role instructions; the Claude tool manifest is client-specific.
## Coordination
The main agent owns task state, decisions, and progress. Subagents report to their parent. The parent forwards only relevant conclusions, references, risks, and constraints; direct peer communication requires a concrete dependency and parent coordination. Subagents cannot create further subagents.
@@ -20,7 +26,7 @@ The shared [orchestration rule](../shared/rules/orchestration.md) defines the `R
## Task state
For long-running work, the main agent maintains one compact state containing `goal`, `decisions`, `changed`, `verified`, `open`, and `risks`. An existing task-state facility is preferred; the file fallback is `.ai-session/state.json` in the current workspace. Subagents may read it when needed, but send updates to the parent. Keep unrelated concurrent tasks in separate checkouts, and keep runtime state out of commits.
See the [canonical task-state policy](../shared/rules/orchestration.md#canonical-task-state) for when to use state and what it may contain. The optional `.ai-session/state.json` file is local handoff state for a long-running active goal, not persistent project memory.
The optional `scripts/commands/session-state.ps1` and `scripts/commands/session-state.sh` helpers update this workspace file. Omitted fields are preserved. Their `-Workspace`/`--workspace` option selects the workspace explicitly; the default is the current working directory. Both accept goal, decisions, changed files, completed verification, open items, and risks. `-Pointer`/`--pointer` only prints the existing file's location.
-5
View File
@@ -1,5 +0,0 @@
# Architecture
Shared Markdown and metadata define meaning once. Codex and Claude adapters contain only client-specific paths, filenames, and serialization details. The build script renders those inputs into `generated/`. Installation is a separate, explicit step that copies generated files into global user-level locations with backups.
Generated output is ignored because it is reproducible build output. The source files are the reviewable record.
+110 -5
View File
@@ -1,8 +1,21 @@
# Configuration
Codex receives a generated global `AGENTS.md`, agent TOML files, skills, rule files, and a `config.toml` adapter. It keeps workspace sandboxing, automatic approval review, `agents.enabled = true`, `agents.max_concurrent_threads_per_session = 5`, and `agents.max_depth = 1`. Claude Code receives a generated global `CLAUDE.md`, agent Markdown files, skills, and `settings.json` with `auto` permissions, explicit `Agent` permission, and five-operation concurrency. Installation resolves user paths at runtime; the repository contains no machine-specific paths.
Source templates are [`adapters/codex/config/config.toml`](../adapters/codex/config/config.toml)
and [`adapters/claude/config/settings.json`](../adapters/claude/config/settings.json).
Installation targets `~/.codex` and `~/.claude`; Codex skills go to `~/.agents/skills`.
Choose the PowerShell or Bash package independently of the client.
Both clients embed `shared/rules/general.md` in their global instructions. Codex loads applicable focused rules from `rules/`; Claude generates them as skills from the shared `adapters/rule-skills.tsv` manifest. Angular, WPF, and UI/UX rules have small entry points with references loaded by topic. `security.md` is the baseline for programming tasks; focused security rules cover authentication, web, API, data, files, network, cryptography, and supply-chain work.
Codex receives a generated global `AGENTS.md`, agent TOML files, skills, rule files, and a `config.toml` adapter.
It sets full access for commands, automatic approval review, `agents.enabled = true`,
`agents.max_concurrent_threads_per_session = 5`, and `agents.max_depth = 1`.
Claude Code receives a generated global `CLAUDE.md`, agent Markdown files, skills, and `settings.json` with
`auto` permissions and explicit `Agent` and `mcporter call context7.*` shell permissions. Where enabled, its sandbox
allows the `mcp.context7.com` domain. The adapter sets a five-operation concurrency default, at most five concurrent
subagents (`CLAUDE_CODE_MAX_CONCURRENT_SUBAGENTS`), and a spawn depth of one (`CLAUDE_CODE_MAX_SUBAGENT_SPAWN_DEPTH`).
Installation resolves user paths at runtime. Active session policy can further restrict these defaults.
Both clients embed `shared/rules/general.md` and the rule-loading conditions from `shared/global-instructions.md`. Rules for languages and frameworks live in their own directories, with an `index.md` entry point and focused Markdown rules under `references/`. Security has its own directory with a baseline entry point and focused rules for authentication, web, APIs, data, files, network, cryptography, and supply chains. Git, Microsoft, and cross-cutting rules remain directly under `shared/rules/`. Codex receives the full directory tree; Claude generates a skill for each rule and copies supporting references alongside the index skill.
The Codex adapter sets `agents.max_depth = 1` and does not enable `features.multi_agent_v2`. Shared instructions also prohibit subagents from creating further subagents. Agent roles are optional, not stages that every task must run.
@@ -12,11 +25,30 @@ Client settings remain thin adapters. Shared semantics remain in `shared/`. User
## Permission defaults
Codex sets `approval_policy = "on-request"`, `approvals_reviewer = "auto_review"`, and `sandbox_mode = "workspace-write"`. Eligible approval requests go through automatic review; sandboxing remains enabled. Claude sets `permissions.defaultMode = "auto"`. These are generated defaults, not a guarantee that a running session, account policy, or explicit launch override uses the same mode.
Codex sets `sandbox_mode = "danger-full-access"`, `approval_policy = "on-request"`, and
`approvals_reviewer = "auto_review"`. All Codex commands run without Codex filesystem or network sandbox
restrictions, under the account that launches Codex. Launch Codex as the repository owner to use that identity;
this configuration does not impersonate another user or change filesystem ownership. OS permissions, firewalls,
and managed organization policies still apply. Eligible approval requests retain automatic review, which does
not restore a filesystem boundary. See the [official OpenAI security documentation](https://learn.chatgpt.com/docs/agent-approvals-security).
The adapter no longer selects the Windows sandbox or workspace writable roots. This avoids using the dedicated
`CodexSandboxOnline` account, whose identity differs from the repository owner and can trigger Git's ownership
check. Old `[windows]` and `[sandbox_workspace_write]` tables may survive an update as preserved local settings;
they do not activate sandboxing while `sandbox_mode` is `danger-full-access`.
Apply the generated configuration through the normal update process, then start a new Codex session under the
repository owner's account. Existing sessions keep their active permissions. Check `whoami` and
`git rev-parse --show-toplevel` there; package validation cannot prove the identity or network access of a future
session. Launch overrides and managed policies may restrict or reject the configured mode.
Claude retains `permissions.defaultMode = "auto"` and shell-specific deny rules. Its sandbox is enabled on
supported macOS, Linux, and WSL2 environments and disabled where unavailable, including native Windows.
These are generated defaults; active session or account policy may differ.
## Status displays
Codex's native `tui.status_line` contains `model`, `reasoning`, `approval-mode`, `project-name`, `git-branch`, `context-window-size`, `context-used`, and `used-tokens`, in that order. `approval-mode` reports the active command review mode. Rendering and colors are controlled by Codex; the adapter does not define custom colors per field.
Codex's native `tui.status_line` contains `model`, `reasoning`, `fast-mode`, `approval-mode`, `five-hour-limit`, `weekly-limit`, `project-name`, `git-branch`, `context-window-size`, `context-used`, and `used-tokens`, in that order. `fast-mode` shows `Fast on` or `Fast off` for supported models; it does not change the selected mode. `five-hour-limit` and `weekly-limit` show remaining usage in the primary and secondary quota windows, typically five hours and one week, and are omitted when Codex has no quota data. `approval-mode` reports the active command review mode. Rendering and colors are controlled by Codex; the adapter does not define custom colors per field. These native fields are supported by [Codex 0.161.0](https://github.com/openai/codex/blob/rust-v0.161.0/codex-rs/tui/src/chatwidget/status_surfaces.rs).
Claude runs `shared/statusline/statusline.ps1` for PowerShell or `statusline.sh` for Bash. Its two-line display is:
@@ -31,10 +63,83 @@ Model and context-window size are cyan, effort and cumulative tokens magenta, re
Claude's status line displays `permission_mode` or `permissionMode` when Claude provides it, and otherwise shows the configured `auto` review mode.
## Local QMD search
Install and update offer **Yes / No / Auto**, with No as the initial default. This option is separate
from the extension selector. The saved `semantic_retrieval` key keeps its name for compatibility.
Quickupdate reuses the saved choice and device; it does not rerun the benchmark.
- **Yes:** install `@tobilu/qmd@2.8.3` if QMD is absent, copy the shared runtime scripts, configure
and download the three models, and choose GPU when detected or CPU otherwise. An existing QMD
installation is reused, not upgraded by this step.
- **Auto:** prepare the same dependencies, then benchmark GPU when available and CPU if needed.
Both thresholds must pass: median warm search latency at most 5 seconds and embedding throughput
at least 20 chunks/second. Each device has a 10-minute timeout. No passing device disables search
and triggers setup-owned resource cleanup. Auto can download models while answering the setup prompt.
- **No:** omit the search skill and its instruction line, remove the warm-up hook registration,
and disable search for the selected clients. Dry runs do not download, benchmark, or remove QMD resources.
The models are Qwen3-Embedding-0.6B, Qwen3-Reranker-0.6B, and QMD Query Expansion 1.7B.
Exact model URIs live in [`shared/qmd/qmd-lib.mjs`](../shared/qmd/qmd-lib.mjs).
Auto thresholds can be overridden with `QMD_BENCHMARK_MAX_QUERY_SECONDS` and
`QMD_BENCHMARK_MIN_CHUNKS_PER_SECOND`. The benchmark uses a temporary database and a deterministic
100-document fixture; its measurements are not an end-to-end estimate for a user's repository.
### Search and storage
The `semantic-search` skill calls the installed wrapper from the current Git repository:
```text
node "$HOME/.my-ai-configuration/qmd/qmd-search.mjs" --query "Where are temporary upload failures retried?" --top-k 5
```
This command works in PowerShell and Bash. `--root` selects a repository explicitly. Results are JSON
objects with `path`, `line`, `score`, and `snippet`; repository hits use relative paths and other collections
use `qmd://` URIs. Known identifiers still use direct reads or `rg`; unknown identifiers use semantic retrieval first.
A token-protected daemon listens on `127.0.0.1`, refreshes changed repository collections, skips git-ignored
paths, and searches the current repository together with the user's default QMD collections. Repository
collections use `repo-` followed by a 12-character path hash. A SessionStart hook warms the daemon and index
in the background. Models stay loaded until the daemon stops after 30 idle minutes, configurable with
`QMD_IDLE_MINUTES`.
On daemon failure the wrapper tries the QMD CLI against the current repository collection only. This fallback
requires an existing index; it does not create or refresh the collection. If the wrapper fails, the skill
reports the limitation and continues with `rg`.
| Location | Contents |
| --- | --- |
| `~/.my-ai-configuration/qmd/` | Runtime scripts, daemon state, locks, collection ownership, and `warm.log`. |
| `~/.my-ai-configuration/qmd.json` | Selected device, enabled clients, and setup ownership records. |
| `$XDG_CACHE_HOME/qmd/` (default `~/.cache/qmd/`) | Shared `index.sqlite` and model cache. |
| `$QMD_CONFIG_DIR/index.yml` | Configuration when `QMD_CONFIG_DIR` is set; otherwise `$XDG_CONFIG_HOME/qmd/index.yml`, defaulting to `~/.config/qmd/index.yml`. |
With the default Codex full-access configuration, QMD uses the launching account's filesystem and network
permissions, including custom cache and configuration paths. If a session overrides this with a sandbox,
permit writes to the runtime directory, resolved cache, and QMD configuration directory. QMD writes configuration
when registering collections and persisting ignore lists.
Disabling search or uninstalling one client keeps the shared runtime while another client remains enabled.
After the last client disables it, cleanup stops the daemon, removes recorded repository collections and
setup-owned models/package, restores the previous `models:` block, and removes the runtime scripts.
It preserves foreign QMD installations, models, collections, and the shared database. Failed cleanup can leave
resources behind; inspect reported warnings rather than deleting the whole cache. Updates also migrate the
old setup-owned Python retrieval directory and QMD extension ownership records.
### Verification and troubleshooting
Check `~/.my-ai-configuration/qmd/warm.log` for background warm-up errors. First startup or changed repositories
can take longer than a warm query. An older session still using the Windows sandbox can fail Git ownership
checks or child-process pipe operations. Apply the configuration and start a new session as described in
[Permission defaults](#permission-defaults).
Model-free unit tests do not verify downloads, GPU support, sandbox access, or real search quality.
See [QMD tests](scripts.md#qmd-tests) for the separate test commands and dependency setup.
## Verification and installation
The agent chooses the smallest sufficient checks based on behavior, affected callers, risk, reversibility, and uncertainty. Inspection can suffice for a small change. Full builds, broad test suites, and independent reviews are not automatic; explicit user and project requirements remain binding.
Delegation and long-running state use the shared orchestration rule, loaded on demand as a Codex rule or Claude skill. The coordinator owns decisions and routes concise evidence-based handoffs. Review and execution verification have separate responsibilities; see [Agents](agents.md).
Rebuild packages after changes to shared definitions or adapters. Generated defaults reach a user's configuration only through installation or update. Updates back up replaced files and preserve Codex's local `model`, `reasoning_effort`, `plugins`, and `marketplaces` settings; other local settings are not generally merged. See [the README](../README.md) for overwrite and backup behavior.
Rebuild packages after changes to shared definitions or adapters. Generated defaults reach a user's configuration only through installation or update. Updates merge Codex's setup-owned root keys and table fields while retaining other root keys, extra fields in managed tables, plugin and marketplace tables, other unmanaged tables such as `mcp_servers` and `model_providers`, and unowned array tables. Claude settings retain unrelated keys and hooks. See [the README](../README.md) for overwrite and backup behavior.
+2 -2
View File
@@ -4,11 +4,11 @@ Shared definitions are the source of truth. Rebuild after every semantic change.
## Add a rule
Create a focused Markdown file in `shared/rules/`. For a rule that applies only to a language, framework, tool, or change area, add one row to `adapters/rule-skills.tsv`. The build uses that manifest to generate both Claude's rule skill and Codex's rule-loading condition. Put always-applicable guidance in `general.md`, which the build embeds for both clients; a new rule file is not automatically embedded.
Create cross-cutting rules such as Git or Microsoft guidance as focused Markdown files directly in `shared/rules/`. Put each language, framework, or library in its own directory with an `index.md` and focused files under `references/`; put security rules in `shared/rules/security/`. Add the matching loading condition and generated Claude skill name to `shared/global-instructions.md` and the directory index. The build copies rule trees to Codex and generates Claude skills from each rule file. Put always-applicable guidance in `general.md`, which the build embeds for both clients; a new rule file is not automatically embedded.
## Add a skill
Create `shared/skills/<category>/<skill>/SKILL.md` with valid YAML frontmatter and a concise workflow. Reference shared rules instead of repeating persistent standards.
Create `shared/skills/<skill>/SKILL.md` for a standalone skill, or `shared/skills/<category>/<skill>/SKILL.md` for a grouped workflow. Each leaf skill directory must contain a readable `SKILL.md` with valid YAML frontmatter. Keep the initial workflow focused; place longer supporting material under `references/`. Reference shared rules instead of repeating persistent standards.
## Add an agent
+5 -2
View File
@@ -9,10 +9,13 @@ The adapters register these events:
| Codex and Claude | `Stop` | Run the finish notification (`flashbang`). |
| Claude | `PreCompact` | Record the compaction timestamp under the installed configuration root and point to existing workspace task state. |
| Claude | `SessionStart` | Print an absolute pointer if the workspace's `.ai-session/state.json` exists. |
| Codex and Claude | `SessionStart` | Warm the QMD index and search daemon in the background (only while local QMD search is enabled). |
The main agent alone maintains canonical task state. Hooks never write or summarize it, print its contents, or infer completed verification. They use the hook event's `cwd`, falling back to the process working directory when no workspace is supplied. Malformed event data does not fall back to another project. An absent state file is a successful no-op. Legacy state under the installed configuration root is not automatically adopted; confirm its task before migrating it. The scripts do not grant permissions, bypass approvals, or replace client permission systems.
The main agent alone maintains canonical task state. Hooks never write or summarize it, print its contents, or infer completed verification. The task-state hooks use the hook event's `cwd`, falling back to the process working directory when no workspace is supplied. Malformed event data does not fall back to another project. An absent state file is a successful no-op. Legacy state under the installed configuration root is not automatically adopted; confirm its task before migrating it. The scripts do not grant permissions, bypass approvals, or replace client permission systems.
When enabled during installation or update, Flashbang runs on `Stop`, after the main agent finishes responding. The default flash lasts about 500 milliseconds. The PowerShell command omits `-WindowStyle Hidden`, which can hide or minimize the shared terminal. The PowerShell hook creates a low-opacity click-through overlay without activating another window when its native GUI APIs are available; unsupported runtimes exit safely. The Bash hook uses Python's `tkinter`, uses `xrandr` for multi-monitor bounds when available, and falls back to `notify-send` when the overlay is unavailable. Registered hooks are best effort: errors do not fail a Claude session.
The QMD warm-up hook uses the process working directory and starts only inside a Git repository when Node.js and the installed wrapper are available. It runs detached; wrapper errors are recorded in `~/.my-ai-configuration/qmd/warm.log`. Disabling local search removes its hook registration. See [Local QMD search](configuration.md#local-qmd-search) for daemon behavior and storage.
When enabled during installation or update, Flashbang runs on `Stop`, after the main agent finishes responding. The default flash lasts about 500 milliseconds. The PowerShell command omits `-WindowStyle Hidden`, which can hide or minimize the shared terminal. The PowerShell hook creates a low-opacity click-through overlay without activating another window when its native GUI APIs are available; unsupported runtimes exit safely. Its native DLL cache is optional: a missing `LOCALAPPDATA` environment variable or an unusable cache falls back to in-process compilation instead of suppressing the notification. The Bash hook uses Python's `tkinter`, uses `xrandr` for multi-monitor bounds when available, and falls back to `notify-send` when the overlay is unavailable. Registered hooks are best effort: errors do not fail a Claude session.
`Validate-CommandSafety`/`validate-command-safety.sh` and `Invoke-PostChangeVerification`/`invoke-post-change-verification.sh` are unregistered utilities. The safety utilities check command text for selected dangerous patterns; the PowerShell variant also checks some absolute paths. Neither is a complete security boundary. The verification utilities explicitly run the repository build when invoked; they are not an automatic requirement after each change.
+40 -5
View File
@@ -2,25 +2,60 @@
The user-level plugin manifest is `adapters/plugins.tsv`. It maps each logical extension to the client-specific plugin, skill, or MCP installation method.
The current baseline includes Ponytail, i-have-adhd, Superpowers, Context7, Caveman, QMD, Humanizer, Impeccable, and Anthropic Frontend Design. Both scripts operate at user scope and show a plugin selector unless running a dry run. Selections are collected before configuration changes. Both rebuild generated packages first.
The current baseline includes Ponytail, i-have-adhd, Superpowers, Context7, Caveman, MCPorter, Humanizer, Impeccable, and Anthropic Frontend Design. Install and update operate at user scope and show an extension selector unless running a dry run or Quickupdate. Selections are collected before configuration changes. Both rebuild generated packages before synchronizing client files and extensions. Choosing Auto for local search can prepare and benchmark QMD earlier, during option selection.
### Automatic workflow integration
The always-loaded general rules route both clients to the shared `plugin-workflow` skill at session start/resume and task or phase changes. The policy requires Superpowers at development phase boundaries, Ponytail for implementation and review, Impeccable for UI planning through verification, and i-have-adhd response structure with Caveman's concise style when available. Superpowers owns process; Ponytail constrains implementation to the smallest complete, verified change; Impeccable owns UI decisions; Frontend Design supplements uncovered needs without starting another workflow. User authorization, research gates, and proportionate checks retain precedence.
The installed i-have-adhd 0.4.1 skill declares `disable-model-invocation: true`. The shared policy therefore supplies automatic response guidance without forcing a manual-only skill invocation or relying on its optional hook. It does not diagnose the user. Style stop commands persist through task changes and resume; `normal mode` disables i-have-adhd, Caveman, and Ponytail for the session. Explicit mode levels override defaults. Missing plugins are reported once and do not trigger installation. These are instruction-level requirements, not runtime interception or a guarantee of model compliance. Existing installations receive them through the normal configuration update; builds do not modify local plugin caches or hook trust.
### Context7 routing
Selecting Context7 with MCPorter registers the server in MCPorter. Selecting Context7 without MCPorter installs its native client plugin; that explicit selection permits the native MCP route under the global instructions.
Both clients receive a mandatory Context7-first research gate through the shared general rules and `technical-research` skill. It triggers whenever answers, planning, coding, reviews, debugging, tests, configuration, or upgrades rely on external technology behavior, without requiring the user to mention Context7. The agent checks project versions, resolves the library, queries the relevant behavior, and verifies the original source. Matching evidence from the same task can be reused across phases and handoffs; repository-only facts need no external call. Missing coverage, version mismatches, and service failures require an explicit fallback to authoritative sources. [Phase checkpoints](skills.md) apply inside plugin workflows as well as the focused shared skills. These are agent instructions, not a runtime enforcement hook.
### Optional Context7 health check
For a configured MCPorter route, run these commands in PowerShell or Bash. They make live requests using a public Angular question; they do not install or change configuration. Routine builds and doctor runs do not run this check.
```text
mcporter list context7 --schema
mcporter call context7.resolve-library-id 'libraryName=Angular' 'query=How do Angular computed signals track dependencies?' --timeout 30000
```
Check that discovery lists `resolve-library-id` and `query-docs` and resolution returns the official Angular documentation. Then query the returned ID (the example assumes `/websites/angular_dev` was returned):
```text
mcporter call context7.query-docs 'libraryId=/websites/angular_dev' 'query=How do Angular computed signals track dependencies?' --timeout 30000
```
The check passes only if documentation retrieval returns relevant content with an original Angular source link. Empty results, error text, or merely a zero process exit code are insufficient. This checks connectivity and one library, not general coverage or agent compliance. For a native plugin installation, run the equivalent discovery and tool calls inside that client; do not add an MCPorter registration just for this check.
### Installation and updates
`install.ps1`/`install.sh` starts every plugin checked by default; unchecking one skips it. It refuses to run against an already-installed destination (`Already installed, use the update script.`).
`update.ps1`/`update.sh` lets you revise the saved extension selection. Checking an extension installs it if missing or updates it if owned; existing foreign installations are preserved. Deselection removes only extensions that this setup installed and recorded as owned. Pre-existing or manually installed plugins and skills are retained. Extensions removed from the manifest are also removed when recorded as owned; unrelated installations are retained. Update refuses to run if any selected destination lacks an installation manifest (`Not installed, use the install script.`).
Codex's local `plugins` and `marketplaces` tables survive configuration synchronization. Cached plugin files alone are not treated as proof of installation: selection uses the client CLI's installed list. If an older update removed the registrations, inspect the backed-up `config.toml` under `~/.codex/backups/` and reselect the affected plugins on the next update.
Codex's local `plugins` and `marketplaces` tables survive configuration synchronization, along with other root keys, extra fields in managed tables, other unmanaged tables, and unowned array tables; changed files are backed up. Cached plugin files alone are not treated as proof of installation: selection uses the client CLI's installed list. If an older update removed the registrations, inspect the backed-up `config.toml` under `~/.codex/backups/` and reselect the affected plugins on the next update.
Codex receives Caveman through its native plugin adapter. Humanizer, Impeccable, and Anthropic Frontend Design are downloaded as skill payloads from the GitHub sources in the manifest, without running upstream installers. All three appear in the extension selector for Codex. Ownership is recorded in `~/.my-ai-configuration/extensions.json`. Skill files are tracked by hash; modified or foreign files are retained with a warning. Existing installations from before ownership tracking are not automatically adopted.
On Windows, installation and update repair the known Caveman 1.0.0 hook launcher in setup-owned Codex installations so it resolves the plugin path under PowerShell as well as Command Prompt. Custom commands and foreign installations are preserved. Review the changed hook definitions in Codex `/hooks`; setup does not grant hook trust automatically.
[QMD](https://github.com/tobi/qmd) requires Node.js 22 or newer and `npm`. Selecting it installs `@tobilu/qmd` globally. Claude receives QMD's official `qmd@qmd` plugin; Codex can use the `qmd` CLI. Deselecting QMD removes setup-owned integrations and uninstalls the global package when the Codex-owned QMD record is removed.
Normal installation and update also ask whether to update the selected client CLIs, enable Flashbang, and enable the optional Qwen3-Embedding-0.6B semantic retrieval layer. Retrieval uses a per-user virtual environment and index and is invoked through the installed `server.py search` CLI, disabled by default. Quickupdate reuses the saved shell, client, CLI update, Flashbang, retrieval, and extension choices without opening menus. Disabling retrieval removes its setup-owned runtime and index. Only successful runs save selections; dry runs do not update CLIs, extensions, or retrieval.
### Setup options outside the extension selector
The `server.py search`/`rebuild` CLI transparently reuses a background daemon (spawned automatically on first use per `--data-dir`) that keeps the embedding and reranking models loaded in memory, so only the first query after a cold start or an idle period pays the model-loading cost; every call falls back to loading the models directly in-process if the daemon cannot be reached or started. The daemon exits on its own after 30 minutes of inactivity. Indexing skips files larger than 512 KB and, per repository, stops after 2000 indexable files by default; set `SEMANTIC_RETRIEVAL_MAX_FILES` to raise that cap for larger monorepos. When the cap is reached, the CLI prints an explicit warning to stderr rather than silently omitting files.
Flashbang, the custom status line, and local QMD search have separate prompts during install and update.
Quickupdate reuses their saved choices together with the shell, client, and extension selection. Only successful
runs save selections; dry runs do not update extensions or local search. Disabling the status line removes its
custom setting and setup-owned Claude script.
QMD is managed by the local-search option, not as a plugin. See [Local QMD search](configuration.md#local-qmd-search)
for models, Auto thresholds, runtime behavior, sandbox paths, and ownership-aware removal.
Install and update do not modify the Codex or Claude CLI installations.
Plugin installation requires the corresponding client CLI, network access, and any authentication required by the plugin. Context7 may open an OAuth flow. Codex or plugin hooks may require a trust review in `/hooks`. The scripts never install plugins during a build or doctor run and never install them when `--dry-run` or `-DryRun` is used.
+86 -12
View File
@@ -15,49 +15,122 @@ Run scripts from the repository root. PowerShell and Bash commands have equivale
| Script | Purpose |
| --- | --- |
| `commands/build.ps1`, `commands/build.sh` | Generate the four client packages in `generated/`. |
| `commands/build.ps1`, `commands/build.sh` | Generate four client packages in `generated/` from the shared skill catalog. |
| `commands/check-capabilities.ps1`, `commands/check-capabilities.sh` | Check required tools and versions. |
| `commands/install.ps1`, `commands/install.sh` | Install a selected client configuration. |
| `commands/update.ps1`, `commands/update.sh` | Update an existing installation; Quick reuses saved choices. |
| `commands/uninstall.ps1`, `commands/uninstall.sh` | Remove setup-owned configuration and extensions. |
| `commands/doctor.ps1`, `commands/doctor.sh` | Check generated output and installed configuration. |
| `commands/prompt-budget.ps1`, `commands/prompt-budget.sh` | Check generated instruction sizes against their budget. |
| `commands/prompt-budget.ps1`, `commands/prompt-budget.sh` | Track permanent context, skill metadata, the rule catalog, and agent metadata; warn above 10,000 permanent-context tokens, fail when any token estimate exceeds its baseline by 10%, or permanent context exceeds 15,000 tokens. |
| `commands/context-report.ps1`, `commands/context-report.sh` | Report the context installed Claude and Codex actually load, from Claude `/context`, `/skill-doctor`, and its init event, and Codex `debug prompt-input`: categories, active plugins, listed skills, installed skills missing from the listing, and skills listed without description context. `--check` fails on missing or description-less skills. No model request is made. |
| `commands/benchmark.ps1`, `commands/benchmark.sh` | Compare real Claude/Codex sessions with and without the setup. See [Session benchmarks](#session-benchmarks) for isolation, costs, and the search comparison. |
| `commands/repository-context.ps1`, `commands/repository-context.sh` | Refresh the local repository-context cache. |
| `commands/session-state.ps1`, `commands/session-state.sh` | Read or update the local agent session state. |
| `commands/telemetry.ps1`, `commands/telemetry.sh` | Append a local telemetry event. |
| `commands/add-instruction.ps1`, `commands/add-instruction.sh` | Append a client-specific user instruction outside managed configuration. |
| `commands/remove-instruction.ps1`, `commands/remove-instruction.sh` | Remove the last exact matching instruction block for a selected client. |
| `commands/add-credentials.ps1`, `commands/add-credentials.sh` | Store a client-scoped tool credential in the operating-system credential store. |
| `commands/remove-credentials.ps1`, `commands/remove-credentials.sh` | Delete a selected client-scoped credential from the operating-system credential store. |
Custom instructions are read before generated rules, skills, and plugins. They remain under `~/.my-ai-configuration/instructions/`, so installation and update scripts never manage or reset them.
Prompt KPIs estimate tokens as UTF-8 bytes divided by four, using the larger shell package per client.
Skill metadata counts every `SKILL.md` frontmatter, including Claude's generated rule skills. Permanent context
combines global instructions, skill and agent metadata, and the security baseline loaded for development tasks.
The rule catalog counts Codex rule files outside `references/` and Claude's generated `rules-*/SKILL.md` entries;
it measures available guidance, not all rules loaded in a typical session. Agent metadata counts Claude frontmatter
and Codex `name`/`description` fields. All metrics fail above baseline +10%; permanent context also warns above
10,000 tokens and fails above 15,000. Project instructions, external plugin bodies, and live MCP/tool schemas
are excluded. `context-report` complements this estimate with installed-client discovery.
On Windows, credentials are stored in Windows Credential Manager. Use `~/.my-ai-configuration/bin/with-credential.ps1` or `.sh` to run a tool with a stored key available only in that child process. The key must be a valid environment-variable name; its value is never written to configuration.
Custom instructions remain under `~/.my-ai-configuration/instructions/`; installation and update scripts never reset their contents. Only clients with a nonempty instruction file receive a startup rule in their installed `AGENTS.md` or `CLAUDE.md`. That rule requires immediate loading before any response or task work and keeps the instructions active throughout the session, including after compaction. Adding or removing instructions refreshes the rule in an existing installation; empty or missing instruction files leave no rule. Generated packages contain no personal instruction rule. Changes apply when the client next loads its global instructions.
To undo an added instruction, pass the same text to `remove-instruction` with `-Client`/`--client` and `-Instruction`/`--instruction`. It removes the last exact matching block per selected client and preserves other text. A missing match leaves the file unchanged.
Qwen retrieval uses `shared/retrieval/benchmark.py`; run it through `scripts/lib/semantic-retrieval.py benchmark --root . --home <home-directory>`.
Credential commands currently require PowerShell and Windows Credential Manager, including their Bash wrappers. Use `~/.my-ai-configuration/bin/with-credential.ps1` or `.sh` to run a tool with a stored key available only in that child process. The key must be a valid environment-variable name; its value is never written to configuration.
Use `remove-credentials` with `-Client`/`--client` and `-Key`/`--key` to delete only that credential. The shared `with-credential` helpers remain installed for other keys.
The A/B benchmark measures whole sessions. Auto selection of local QMD search uses `shared/qmd/qmd-benchmark.mjs`, run through `scripts/lib/qmd.py`. It measures median search latency and embedding throughput on GPU, then CPU, and is not an end-to-end performance estimate.
## Checks and tests
Gitea Actions runs the repository checks from `.gitea/workflows/ci.yml`.
Doctor captures native-command diagnostics and checks exit codes. A warning on stderr does not abort the
PowerShell 5.1 script; failed version or configuration checks contribute to the final failure summary.
On Windows, an unavailable profile-folder lookup falls back to PowerShell's home path.
| Script | Purpose |
| --- | --- |
| `checks/validate-config.py` | Validate generated Codex TOML and Claude JSON. |
| `tests/test-build-validation.ps1`, `tests/test-build-validation.sh` | Validate build failures and generated output. |
| `tests/test-capabilities.ps1` | Guard PowerShell capability detection. |
| `tests/test-install-guards.ps1`, `tests/test-install-guards.sh` | Validate install and update guard conditions. |
| `tests/test-config-effects.py` | Check that generated limits and permissions take effect: Codex keeps the V1 multi-agent implementation that honors `agents.max_depth`; with `AI_CONFIG_LIVE_TESTS=1`, short Haiku sessions confirm that Claude withholds the Agent tool from subagents, refuses subagents above the concurrency limit, and blocks `git reset --hard` in every shell tool. |
| `tests/test-client-smoke.py` | Install a package into a temporary home with foreign settings and ask the installed Claude and Codex CLIs which skills, agents, and hooks they discover, without completing a model request. Skips a client whose CLI is unavailable unless `AI_CONFIG_REQUIRE_CLIENTS=1`, which the CI `client-smoke` job sets. |
| `tests/test-install-options.py` | Validate interactive option handling and generated manifest changes. |
| `tests/test-managed-extensions.py` | Validate plugin, skill, and CLI ownership handling. |
| `tests/test-managed-install.ps1`, `tests/test-managed-install.sh` | Validate managed-file synchronization and backups. |
| `tests/test-plugin-selection.ps1`, `tests/test-plugin-selection.sh` | Validate plugin selection. |
| `tests/test-prompt-budget.py` | Validate prompt budget threshold evaluation. |
| `tests/test-prompt-inventory.py` | Validate prompt inventory collection. |
| `tests/test-quick-update.py` | Validate saved Quickupdate choices. |
| `tests/test-remove-customizations.py` | Validate targeted instruction and credential removal without accessing the real credential store. |
| `tests/test-quick-update.ps1`, `tests/test-quick-update.sh` | Run the Quickupdate test through the relevant shell. |
| `tests/test-retrieval-server.py` | Validate retrieval indexing, ranking, and optional real-model execution. |
| `tests/test-semantic-retrieval.py` | Validate retrieval installation and removal. |
| `tests/test-qmd-lib.mjs`, `test-qmd-daemon.mjs`, `test-qmd-search.mjs`, `test-qmd-warm.mjs`, `test-qmd-benchmark.mjs` | Model-free QMD unit tests; require the YAML dependency. |
| `tests/test-qmd-integration.mjs` | Manual integration test using real QMD and downloaded models; excluded from CI. |
| `tests/test-qmd-setup.py` | Validate QMD installation, migration, and removal. |
| `tests/test-session-state.py` | Validate session-state helpers. |
| `tests/test-shell-packages.ps1`, `tests/test-shell-packages.sh` | Validate generated package contents and client settings. |
| `tests/test-runtime-status.ps1`, `tests/test-runtime-status.sh` | Validate build summaries and status-line output. |
| `tests/test-install-selections.ps1`, `tests/test-install-selections.sh` | Validate dry-run shell and client selections. |
| `tests/test-command-summaries.ps1`, `tests/test-command-summaries.sh` | Validate doctor, install, and update summary output. |
| `tests/test-telemetry.py` | Validate telemetry output. |
| `tests/test-personal-instructions.py` | Validate startup instruction pointers and preservation of personal instruction files. |
| `tests/test-user-customizations.py` | Validate user instruction overlays and credential helpers. |
## QMD tests
The CI `qmd` job installs only `yaml@2.9.0` into an isolated directory, sets `QMD_PACKAGE_DIR` to that directory,
and runs these five files. It does not install QMD or download models. With a complete global QMD installation,
the same tests resolve YAML from QMD automatically:
```text
node --test scripts/tests/test-qmd-lib.mjs scripts/tests/test-qmd-daemon.mjs scripts/tests/test-qmd-search.mjs scripts/tests/test-qmd-warm.mjs scripts/tests/test-qmd-benchmark.mjs
```
Without QMD installed, use the dependency setup from [the CI workflow](../.gitea/workflows/ci.yml).
`QMD_PACKAGE_DIR` must point to the directory containing the test dependency's `node_modules` directory.
A missing YAML dependency fails `test-qmd-lib.mjs` before its tests load.
Run the integration test separately, only with a complete QMD installation and resources for model downloads.
Unset `QMD_CONFIG_DIR` first so the test uses its temporary configuration rather than an inherited user path.
Clear a unit-test-only `QMD_PACKAGE_DIR` override as well:
```text
node --test scripts/tests/test-qmd-integration.mjs
```
The integration test creates a temporary home and repository, downloads models, searches through the daemon,
and stops it after successful assertions.
Its temporary data is not automatically removed. `QMD_TEST_CACHE` can select an existing QMD cache parent;
the test uses its `qmd/` subdirectory, so avoid pointing it at a cache containing unrelated data.
## Session benchmarks
The A/B benchmark runs Python, C#/ASP.NET, and TypeScript tasks under `scripts/benchmarks/tasks/`.
These are real model sessions and can incur usage charges; `--dry-run` lists planned runs.
Both arms use the same model and reasoning effort for each client. Preflight records loaded configuration in
`provenance.json` and normally stops when the arms are not comparable. Reports compare pass rate, rework turns,
time, tokens, tool calls, cost, and workflow checks per task category.
For Claude's semantic-search comparison, pass these arguments to the shell's benchmark command:
```text
--clients claude --arms setup setup-no-search --tasks 11-* 12-* 13-* --warm-index
```
`setup-no-search` is Claude-only. Warm-up starts QMD and indexes the fixture before timing setup-arm sessions.
The Codex baseline requires a separate login under `--codex-baseline-home`; set `CODEX_HOME` to that path for
`codex login`. Supply `--codex-model` if the installed configuration does not select a model.
Benchmark fixture READMEs describe the starting task state and are retained as test inputs.
## Internal helpers
@@ -65,14 +138,15 @@ Gitea Actions runs the repository checks from `.gitea/workflows/ci.yml`.
| --- | --- |
| `lib/install-options.ps1`, `lib/install-options.sh` | Read installation options and calculate client-specific choices. |
| `lib/credentials.ps1`, `lib/with-credential.sh` | Write a tool credential to Windows Credential Manager and expose it to one child process. |
| `lib/install-options.py` | Filter configuration templates according to installation options. |
| `lib/install-options.py` | Filter configuration templates and merge setup-owned client settings with local configuration. |
| `lib/install-targets.ps1`, `lib/install-targets.sh` | Resolve configuration targets for the selected client and shell. |
| `lib/manifest.ps1`, `lib/manifest.sh` | Synchronize managed files and their ownership manifest. |
| `lib/plugins.ps1`, `lib/plugins.sh` | Select and install configured plugins. |
| `lib/managed-extensions.py` | Reconcile CLI extensions and MCPorter-managed plugins. |
| `lib/prompt-inventory.py` | Collect prompt files for the build. |
| `lib/prompt-inventory.py` | Report generated, installed, and cached skill counts for prompt-budget checks. |
| `lib/remove-instruction.py` | Remove an exact client-specific instruction block. |
| `lib/selection-state.ps1`, `lib/selection-state.sh` | Persist choices used by Quickupdate. |
| `lib/selection-state.py` | Read and write Quickupdate state. |
| `lib/semantic-retrieval.ps1`, `lib/semantic-retrieval.sh` | Invoke semantic retrieval from the installation flow. |
| `lib/semantic-retrieval.py` | Install, index, benchmark, and remove the local retrieval service. |
| `shared/retrieval/benchmark.py` | Measure Qwen embedding and reranking speed for the Auto recommendation. |
| `lib/qmd.sh`, `lib/qmd.ps1` | Invoke local QMD search from the installation flow. |
| `lib/qmd.py` | Install, migrate, benchmark, and remove local QMD search. |
| [`shared/qmd/`](../shared/qmd/) (repository root) | Installed QMD scripts: search CLI, daemon, warm-up, benchmark, and shared library. |
+27 -14
View File
@@ -1,25 +1,38 @@
# Skills
Skills are reusable workflows. Rules are persistent constraints and agents are specialized roles. Each skill is a minimal `SKILL.md` with YAML frontmatter and a small initial workflow so both clients can consume it.
Skills are reusable workflows. Rules are persistent constraints and agents are specialized roles. Each skill has a readable `SKILL.md` with YAML frontmatter; detailed guidance may live in that file or its `references/` directory.
The current structure is organized by purpose:
- `debugging/`
- `planning/`: implementation planning, impact analysis, and work-item definition
- `research/`: technical and repository research
- `reviews/`: code, security, performance, WPF, UI/UX, business, API, and EF Core reviews
- `planning/`: impact analysis and work-item definition
- `research/`: mandatory `research` gate for every search, with technical and repository specialists, plus `semantic-search`, which is installed only while local QMD search is enabled
- `reviews/`: security, performance, WPF, UI/UX, business, API, and EF Core reviews
- `implementation/`: SQL, unit-test, and integration-test writing
- `verification/`: facts, work-item, and regression verification
- `git/`: pull request responses and reviews
- `verification/`: facts and work-item verification
- `git/`: pull request reviews
- `content-strategy/`, `copy-editing/`, `copywriting/`: planning, editing, and writing text
- `image/`: image assets, screenshots, SEO and performance, social-preview metadata, practical marketing workflows, design tools, and common mistakes
- `site-architecture/`: website structure
- `marketing-psychology/`, `offers/`, `product-marketing/`, `cro/`: audience understanding, value framing, and conversion
The files intentionally define only a small baseline. Detailed personal workflows and standards can be added later without changing the structure.
General planning, debugging, code review, and completion verification workflows come from Superpowers, so the catalog does not duplicate their triggers. The remaining skills cover focused domains Superpowers does not.
Claude's generated package additionally has `skills/rules/`: one skill per technology- or situation-specific rule in
`shared/rules/` (driven by the shared `adapters/rule-skills.tsv` manifest), so the full rule text loads only when Claude invokes the
matching skill instead of sitting permanently in context. This category does not exist for Codex, which keeps loading
applicable focused rules as plain files instead. Both clients embed the general rules in their global instructions.
Split Angular, WPF, and UI/UX rules load supporting references only for the topic being worked on. See [Configuration](configuration.md).
The shared `plugin-workflow` skill coordinates automatic plugin use: Superpowers for process, Ponytail for implementation and review, Impeccable for UI, and i-have-adhd with Caveman for responses. Global instructions require it at session start/resume and task or phase changes. It routes to installed skills, preserves explicit opt-outs, and handles missing or manual-only plugins without replacing upstream workflows.
Skills guide a task when needed; their availability does not require a full review, build, or test suite after every
Each skill defines a focused workflow with the investigation, decision points, and output expected for that task. Keep guidance specific to the skill; shared repository constraints belong in the rules.
The single catalog in `shared/skills/` includes development skills and focused skills for writing, image assets, content and site structure, positioning, psychology, and conversion. The image skill has a short core and five focused references loaded only when relevant: optimization, OG metadata, marketing workflows, design tools, and common mistakes. AI-generation guides, model comparisons, prompting recipes, and fixed social-platform size catalogs are omitted. Builds include every retained skill for both clients. Updating a managed installation backs up and removes unchanged setup-owned skills deleted from the catalog; local changes are backed up and retained.
Claude discovers only `skills/<name>/SKILL.md`, so its generated package flattens the categorized catalog to one directory per skill name, together with the skill's `references/`; the build fails on duplicate names or a `name` that differs from its directory. Claude's package additionally has a `rules-*` skill for each focused rule file or directory in
`shared/rules/`. The rule-to-skill loading conditions live in `shared/global-instructions.md`, so full rule text loads
only when Claude invokes a matching skill instead of sitting permanently in context. Codex reads the matching rule
files directly. Both clients embed the general rules in their global instructions.
Language, framework, library, and security rules use directory indexes plus focused topic files. Their generated Claude skills expose each focused rule separately; the index skills also include the references for contextual lookup. See [Configuration](configuration.md).
Every search or lookup must use `research` and the applicable specialist, including direct reads, exact matches, familiar areas, and follow-up queries during implementation or verification. Loaded instructions can be reused; their checks apply to each search. Semantic retrieval runs first for unknown repository identifiers; known identifiers still use direct reads or `rg` within the research workflow. Disabling QMD does not disable the research requirement. These are agent instructions, not a runtime tool interceptor.
Context7 phase checkpoints are defined once in `research/technical-research/SKILL.md`. Focused planning, SQL and test-writing, and verification skills call them explicitly, as do the architect, implementer, and verifier roles. The global rule applies the same checkpoints inside Superpowers and other plugin workflows without modifying upstream plugin caches or duplicating general workflow skills. Planning verifies external assumptions before accepting a design; implementation checks them against actual versions before coding; verification requires both applicable source evidence and proportionate execution results. Evidence travels in the existing plan or handoff and is reused across phases when the behavior, version, and environment match. Queries contain only public, sanitized concepts, use bounded timeouts and refinement, and report source fallback or unresolved gaps explicitly. This enforces an instruction contract; it does not guarantee model compliance or add network calls to builds and tests.
Other skills guide a task when needed; their availability does not require a full review, build, or test suite after every
change. The shared Verification rules govern proportional checking, including when generic skill workflows call
for more work than the change needs.
+493
View File
@@ -0,0 +1,493 @@
"""Run the benchmark tasks with and without the installed setup and compare the results.
Each run copies a task fixture into a fresh Git repository, gives the client the task prompt,
then runs hidden checks the agent never saw. A failed check gets one rework turn with the check
output. Results land in <out>/results.jsonl and <out>/summary.md.
Arms:
setup the installed configuration (CLAUDE.md, settings, plugins, skills, MCP servers).
baseline Claude with --setting-sources "" --strict-mcp-config (no user settings, plugins,
user skills, CLAUDE.md, or MCP servers); Codex with CODEX_HOME set to --codex-baseline-home,
an empty home where you ran `codex login` once, with every user and plugin skill disabled.
Both arms of a client use the same pinned model and reasoning effort. Before any run, a preflight
records what each arm actually loads (model, effort, skills by source, plugins, MCP servers,
instructions) in <out>/provenance.json and stops if the arms are not comparable.
"""
import argparse
import fnmatch
from concurrent.futures import ThreadPoolExecutor
import json
import os
from pathlib import Path
import queue
import re
import shutil
import statistics
import subprocess
import sys
import tempfile
import threading
import time
TASKS = Path(__file__).resolve().parent / 'tasks'
CHECK = [sys.executable, '-m', 'unittest', 'discover', '-s', 'bench_hidden', '-t', '.']
CLAUDE_TOOLS = ['Read', 'Edit', 'Write', 'Glob', 'Grep', 'Agent', 'Skill', 'TodoWrite', 'Bash(python *)', 'Bash(git *)',
'Bash(ls *)', 'Bash(dotnet *)', 'Bash(node *)', 'PowerShell(python *)', 'PowerShell(git *)', 'PowerShell(Get-ChildItem *)',
'PowerShell(dotnet *)', 'PowerShell(node *)']
def clean_env(**values):
env = {key: value for key, value in os.environ.items() if not key.startswith(('BUN_INSPECT', 'CLAUDECODE', 'CLAUDE_CODE_ENTRYPOINT'))}
env.update(values)
return env
def kill_tree(process):
if os.name == 'nt':
subprocess.run(['taskkill', '/T', '/F', '/PID', str(process.pid)], capture_output=True, timeout=30)
else:
process.kill()
process.wait(timeout=30)
def run_jsonl(command, cwd, env, timeout, prompt):
"""Run a client, return (events, seconds, timed_out); output is read on a thread so the deadline holds.
The prompt goes through stdin: on Windows the clients start through .cmd shims that cut arguments at newlines.
"""
start = time.monotonic()
process = subprocess.Popen(command, cwd=cwd, env=env, stdin=subprocess.PIPE, stdout=subprocess.PIPE,
stderr=subprocess.DEVNULL, text=True, encoding='utf-8', errors='replace')
threading.Thread(target=lambda: (process.stdin.write(prompt), process.stdin.close()), daemon=True).start()
lines = queue.Queue()
threading.Thread(target=lambda: ([lines.put(line) for line in process.stdout], lines.put(None)), daemon=True).start()
events, timed_out = [], False
while True:
try:
line = lines.get(timeout=max(1, timeout - (time.monotonic() - start)))
except queue.Empty:
timed_out = True
break
if line is None:
break
try:
events.append(json.loads(line))
except ValueError:
pass
kill_tree(process) if process.poll() is None else process.wait()
return events, time.monotonic() - start, timed_out
def claude_flags(arm, args):
flags = ['--model', args.claude_model, '--effort', args.claude_effort]
if arm == 'baseline':
flags += ['--setting-sources', '', '--strict-mcp-config']
if arm == 'setup-no-search':
flags += ['--disallowedTools', 'Skill(semantic-search)', 'Bash(*qmd-search*)', 'PowerShell(*qmd-search*)',
'--append-system-prompt', 'The semantic-search skill and the QMD search wrapper are unavailable in this session.']
return flags
def codex_env(arm, args):
return clean_env(CODEX_HOME=str(args.codex_baseline_home)) if arm == 'baseline' else clean_env()
def claude_turn(prompt, cwd, arm, args, session):
command = [shutil.which('claude'), '-p', '--output-format', 'stream-json', '--verbose',
'--permission-mode', 'auto', '--allowedTools', *CLAUDE_TOOLS, *claude_flags(arm, args)]
if session:
command += ['--resume', session]
timeout = args.timeout
events, seconds, timed_out = run_jsonl(command, cwd, clean_env(), timeout, prompt)
result = next((event for event in reversed(events) if event.get('type') == 'result'), {})
usage = result.get('usage', {})
calls = [block for event in events if event.get('type') == 'assistant'
for block in event.get('message', {}).get('content', []) if block.get('type') == 'tool_use']
commands = [str(call.get('input', {}).get('command', '')) for call in calls if call.get('name') in ('Bash', 'PowerShell')]
return {
'session': result.get('session_id') or session, 'seconds': seconds, 'timed_out': timed_out,
'input_tokens': usage.get('input_tokens', 0) + usage.get('cache_read_input_tokens', 0) + usage.get('cache_creation_input_tokens', 0),
'output_tokens': usage.get('output_tokens', 0), 'cost_usd': result.get('total_cost_usd') or 0,
'tool_calls': len(calls), 'agents': sum(call.get('name') == 'Agent' for call in calls),
'skills': [str(call.get('input', {}).get('skill', '')) for call in calls if call.get('name') == 'Skill'],
'commands': commands, 'final': str(result.get('result', '')),
'models': sorted({str(event['message']['model']) for event in events
if event.get('type') == 'assistant' and event.get('message', {}).get('model')}),
'error': str(result.get('result', '') or 'no result event')[:300] if result.get('is_error') or not result else '',
}
def codex_turn(prompt, cwd, arm, args, session):
command = [shutil.which('codex'), 'exec']
if session:
command += ['resume', session]
# `exec resume` rejects --sandbox; the config key works for both forms.
command += ['--json', '--skip-git-repo-check', '-c', 'sandbox_mode="workspace-write"',
'-m', args.codex_model, '-c', f'model_reasoning_effort="{args.codex_effort}"']
command += ['-C', str(cwd)] if not session else []
command.append('-')
events, seconds, timed_out = run_jsonl(command, cwd, codex_env(arm, args), args.timeout, prompt)
items = [event.get('item', {}) for event in events if event.get('type') == 'item.completed']
tools = [item for item in items if item.get('type') not in ('agent_message', 'reasoning', 'error')]
usage = [event.get('usage', {}) for event in events if event.get('type') == 'turn.completed']
thread = next((event.get('thread_id') for event in events if event.get('type') == 'thread.started'), session)
return {
'session': thread, 'seconds': seconds, 'timed_out': timed_out,
'input_tokens': sum(entry.get('input_tokens', 0) for entry in usage),
'output_tokens': sum(entry.get('output_tokens', 0) for entry in usage), 'cost_usd': 0,
'tool_calls': len(tools), 'agents': sum(item.get('type') == 'collab_tool_call' for item in tools),
'skills': [], 'commands': [str(item.get('command', '')) for item in tools if item.get('type') == 'command_execution'],
'final': next((str(item.get('text', '')) for item in reversed(items) if item.get('type') == 'agent_message'), ''),
'models': [args.codex_model],
'error': next((str(event.get('message', event.get('error', '')))[:300] for event in events if event.get('type') in ('error', 'turn.failed')
and not str(event.get('message', '')).startswith('Reconnecting')), 'no turn.completed event') if not usage else '',
}
class AppServer:
"""Minimal JSON-RPC client for `codex app-server`; every wait has a deadline."""
def __init__(self, env, cwd):
self.process = subprocess.Popen([shutil.which('codex'), 'app-server'], cwd=cwd, env=env, stdin=subprocess.PIPE,
stdout=subprocess.PIPE, stderr=subprocess.DEVNULL, text=True, encoding='utf-8')
self.lines, self.next_id = queue.Queue(), 0
threading.Thread(target=lambda: [self.lines.put(line) for line in self.process.stdout], daemon=True).start()
self.call('initialize', {'clientInfo': {'name': 'ai-config-benchmark', 'version': '1'}})
self.process.stdin.write(json.dumps({'jsonrpc': '2.0', 'method': 'initialized'}) + '\n')
def call(self, method, params):
self.next_id += 1
self.process.stdin.write(json.dumps({'jsonrpc': '2.0', 'id': self.next_id, 'method': method, 'params': params}) + '\n')
self.process.stdin.flush()
while True:
message = json.loads(self.lines.get(timeout=120))
if message.get('id') == self.next_id:
if 'error' in message:
raise RuntimeError(f'{method}: {message["error"]}')
return message['result']
def close(self):
kill_tree(self.process)
def codex_configured(env, cwd):
server = AppServer(env, cwd)
try:
return server.call('config/read', {})['config']
finally:
server.close()
def codex_provenance(arm, args, cwd):
server = AppServer(codex_env(arm, args), cwd)
try:
config = server.call('config/read', {})['config']
listing = lambda: server.call('skills/list', {'cwds': [str(cwd)], 'forceReload': True})['data'][0]['skills']
skills = listing()
if arm == 'baseline':
# Codex reads ~/.agents/skills from the real profile even with another CODEX_HOME; disable those skills there.
for skill in skills:
if skill.get('enabled', True) and (skill.get('scope') == 'user' or skill.get('pluginId')):
server.call('skills/config/write', {'path': skill['path'], 'enabled': False})
skills = listing()
finally:
server.close()
prompt = subprocess.run([shutil.which('codex'), 'debug', 'prompt-input', '-c', f'model="{args.codex_model}"',
'-c', f'model_reasoning_effort="{args.codex_effort}"', 'provenance probe'],
cwd=cwd, env=codex_env(arm, args), capture_output=True, text=True, encoding='utf-8', timeout=180).stdout
setup_agents = Path.home() / '.codex' / 'AGENTS.md'
marker = next((line.strip() for line in setup_agents.read_text(encoding='utf-8-sig').splitlines() if line.strip()), '') if setup_agents.is_file() else ''
enabled = [skill for skill in skills if skill.get('enabled', True)]
return {
'model': args.codex_model, 'effort': args.codex_effort,
'configured_model': config.get('model'), 'configured_effort': config.get('model_reasoning_effort'),
'sandbox_mode': config.get('sandbox_mode'), 'approval_policy': config.get('approval_policy'),
'skills_by_scope': {scope: sum(skill.get('scope') == scope and not skill.get('pluginId') for skill in enabled)
for scope in sorted({skill.get('scope') for skill in enabled})},
'plugin_skills': sorted(skill['name'] for skill in enabled if skill.get('pluginId')),
'user_skills': sorted(skill['name'] for skill in enabled if skill.get('scope') == 'user' and not skill.get('pluginId')),
'mcp_servers': sorted(config.get('mcp_servers') or {}),
'global_instructions_loaded': bool(marker) and marker in prompt,
'prompt_input_tokens_estimate': len(prompt.encode('utf-8')) // 4,
}
def claude_provenance(arm, args, cwd):
claude = shutil.which('claude')
process = subprocess.Popen([claude, '-p', 'provenance probe', '--output-format', 'stream-json', '--verbose', *claude_flags(arm, args)],
cwd=cwd, env=clean_env(), stdin=subprocess.DEVNULL, stdout=subprocess.PIPE, stderr=subprocess.DEVNULL,
text=True, encoding='utf-8')
lines = queue.Queue()
threading.Thread(target=lambda: [lines.put(line) for line in process.stdout], daemon=True).start()
try:
init = {}
while init.get('subtype') != 'init':
init = json.loads(lines.get(timeout=180))
finally:
kill_tree(process)
context = json.loads(subprocess.run([claude, '-p', '/context', '--output-format', 'json', *claude_flags(arm, args)], cwd=cwd, env=clean_env(),
capture_output=True, text=True, encoding='utf-8', timeout=180).stdout).get('result', '')
def rows(heading):
section = re.search(rf'(?ms)^### {re.escape(heading)}\s*$(.*?)(?=^### |\Z)', context)
cells = [[cell.strip() for cell in line.strip().strip('|').split('|')] for line in (section.group(1) if section else '').splitlines() if line.startswith('|')]
return [row for row in cells[2:] if row and row[0]]
sources = {}
for row in rows('Skills'):
source = row[1].split(' (')[0] if len(row) > 1 else '?'
sources[source] = sources.get(source, 0) + 1
model = re.search(r'\*\*Model:\*\*\s*(\S+)', context)
return {
'model': init.get('model') or (model.group(1) if model else None), 'effort': args.claude_effort,
'permission_mode': init.get('permissionMode'),
'skills_by_source': sources, 'skills_listed': len(init.get('skills', [])),
'plugins': sorted(plugin.get('name', str(plugin)) if isinstance(plugin, dict) else str(plugin) for plugin in init.get('plugins', [])),
'mcp_servers': sorted(server.get('name', str(server)) if isinstance(server, dict) else str(server) for server in init.get('mcp_servers', [])),
'memory_files': [row[1] for row in rows('Memory Files') if len(row) > 1],
}
def preflight(args, clients, arms):
"""Record what each arm loads and return the problems that make the comparison invalid."""
provenance, problems = {}, []
with tempfile.TemporaryDirectory(prefix='ai-bench-preflight-', ignore_cleanup_errors=True) as directory:
subprocess.run(['git', 'init', '-q'], cwd=directory, check=True, timeout=60)
for client in clients:
for arm in arms:
if client == 'codex' and arm == 'setup-no-search':
continue
data = (claude_provenance if client == 'claude' else codex_provenance)(arm, args, Path(directory))
provenance[f'{client}/{arm}'] = data
if client == 'claude' and arm == 'baseline':
if set(data['skills_by_source']) - {'Built-in'}:
problems.append(f'claude baseline loads non-built-in skills: {data["skills_by_source"]}')
if data['memory_files'] or data['mcp_servers']:
problems.append(f'claude baseline loads memory files {data["memory_files"]} or MCP servers {data["mcp_servers"]}')
if client == 'codex' and arm == 'baseline':
if data['user_skills'] or data['plugin_skills']:
problems.append(f'codex baseline still enables user or plugin skills: {data["user_skills"] + data["plugin_skills"]}')
if data['global_instructions_loaded'] or data['mcp_servers']:
problems.append('codex baseline loads the global AGENTS.md or MCP servers')
models = {provenance[key]['model'] for key in provenance if key.startswith(client + '/')}
if len(models) > 1:
problems.append(f'{client} arms resolve to different models: {sorted(models)}')
return provenance, problems
QMD_SCRIPTS = Path.home() / '.my-ai-configuration/qmd'
FILLER_TOPICS = [
('statement', 'download', 'Render a statement download for the export queue.'),
('trial', 'banner', 'Show the trial banner text in the marketing header.'),
('upload', 'progress', 'Track upload progress for the dashboard widget.'),
('network', 'status', 'Describe the network status shown in the footer.'),
('invoice', 'label', 'Format the invoice label printed on envelopes.'),
('retry', 'hint', 'Return the retry hint shown next to a failed form field.'),
('cent', 'display', 'Format a cent amount for the price badge.'),
('customer', 'greeting', 'Pick the greeting for a customer newsletter.'),
]
def generate_filler(work, count):
"""Write deterministic distractor modules that share vocabulary with the task prompts but not their logic."""
for number in range(count):
noun, verb, doc = FILLER_TOPICS[number % len(FILLER_TOPICS)]
name = f'{noun}_{verb}_{number:03d}'
path = work / 'app' / 'modules' / f'{name}.py'
path.parent.mkdir(parents=True, exist_ok=True)
body = [f'def {name}(value, locale="en"):', f' """{doc}"""', ' text = str(value).strip()',
f' return f"{{locale}}:{noun}:{verb}:{{text}}"', '']
path.write_text('\n'.join(body), encoding='utf-8')
(work / 'app' / 'modules' / '__init__.py').write_text('', encoding='utf-8')
def warm_index(work):
"""Index the fixture and start the QMD daemon before the session, as in a repository that was searched before."""
script = QMD_SCRIPTS / 'qmd-warm.mjs'
if script.is_file():
subprocess.run(['node', str(script), '--root', str(work)], capture_output=True, timeout=1800)
def check(work, task):
hidden = work / 'bench_hidden'
shutil.rmtree(hidden, ignore_errors=True)
shutil.copytree(task / 'hidden', hidden)
spec = json.loads((task / 'task.json').read_text(encoding='utf-8'))
command = CHECK
if spec.get('check'):
program, *arguments = spec['check']
command = [sys.executable if program == 'python' else shutil.which(program) or program, *arguments]
result = subprocess.run(command, cwd=work, capture_output=True, text=True, encoding='utf-8', errors='replace', timeout=600)
shutil.rmtree(hidden, ignore_errors=True)
return result.returncode == 0, (result.stdout + result.stderr)[-3000:]
def workflow_violations(spec, turns):
skills = [skill for turn in turns for skill in turn['skills']]
agents = sum(turn['agents'] for turn in turns)
calls = sum(turn['tool_calls'] for turn in turns)
commands = [command for turn in turns for command in turn['commands']]
problems = [f'used planning skill {skill}' for skill in skills if skill in spec.get('forbid_skills', [])]
if agents > spec.get('max_agents', 99):
problems.append(f'{agents} agents > {spec["max_agents"]}')
if agents < spec.get('min_agents', 0):
problems.append(f'{agents} agents < {spec["min_agents"]}')
if calls > spec.get('max_tool_calls', 10 ** 6):
problems.append(f'{calls} tool calls > {spec["max_tool_calls"]}')
if spec.get('require_command') and not any(re.search(spec['require_command'], command) for command in commands):
problems.append(f'no command matching {spec["require_command"]}')
return problems
def run_one(job, args):
client, arm, task, repetition = job
spec = json.loads((task / 'task.json').read_text(encoding='utf-8'))
with tempfile.TemporaryDirectory(prefix=f'ai-bench-{task.name[:2]}-', ignore_cleanup_errors=True) as directory:
work = Path(directory)
shutil.copytree(task / 'repo', work, dirs_exist_ok=True)
if spec.get('generate', {}).get('filler_modules'):
generate_filler(work, spec['generate']['filler_modules'])
for git in (['init', '-q'], ['add', '-A'], ['-c', 'user.name=bench', '-c', 'user.email=bench@example.invalid', 'commit', '-qm', 'fixture']):
subprocess.run(['git', '-c', 'core.autocrlf=false', *git], cwd=work, check=True, timeout=60)
if args.warm_index and arm == 'setup':
warm_index(work)
turns, prompt, session = [], spec['prompt'], None
for round_number in range(1 + args.rework):
turn = (claude_turn if client == 'claude' else codex_turn)(prompt, work, arm, args, session)
turns.append(turn)
session = turn['session']
if turn['error']:
passed, output = False, ''
break
passed, output = check(work, task)
if passed or turn['timed_out'] or not session:
break
prompt = f'The acceptance checks failed:\n\n{output}\n\nFix the code so they pass.'
if not passed and args.keep_failed:
shutil.copytree(work, args.out / 'failed' / f'{client}-{arm}-{task.name}-{repetition}', ignore=shutil.ignore_patterns('.git'))
return {
'client': client, 'arm': arm, 'task': task.name, 'repetition': repetition, 'passed': passed,
'error': next((turn['error'] for turn in turns if turn['error']), ''),
'first_try': passed and len(turns) == 1, 'rework_turns': len(turns) - 1,
'seconds': round(sum(turn['seconds'] for turn in turns), 1),
'input_tokens': sum(turn['input_tokens'] for turn in turns), 'output_tokens': sum(turn['output_tokens'] for turn in turns),
'cost_usd': round(sum(turn['cost_usd'] for turn in turns), 4), 'tool_calls': sum(turn['tool_calls'] for turn in turns),
'agents': sum(turn['agents'] for turn in turns), 'skills': [skill for turn in turns for skill in turn['skills']],
'commands': [command for turn in turns for command in turn['commands']],
'models': sorted({model for turn in turns for model in turn['models']}),
'searches': sum('qmd-search' in command for turn in turns for command in turn['commands'])
+ sum(skill == 'semantic-search' for turn in turns for skill in turn['skills']),
'timed_out': any(turn['timed_out'] for turn in turns), 'workflow_kind': spec['workflow'].get('kind'),
'workflow_violations': workflow_violations(spec['workflow'], turns), 'check_output': '' if passed else output,
}
def summarize(results):
errors = [result for result in results if result.get('error')]
results = [result for result in results if not result.get('error')]
lines = [f'Excluded {len(errors)} runs that ended with a client or API error (for example a usage limit).',
'Rows are per task category; an overall average would hide a category where one arm is worse.', '',
'| category | client | arm | runs | pass | first try | rework turns | median s | median input tok | median output tok | median tool calls | cost USD | workflow ok |',
'|---|---|---|---|---|---|---|---|---|---|---|---|---|']
groups = {}
for result in results:
spec = TASKS / result['task'] / 'task.json'
category = json.loads(spec.read_text(encoding='utf-8')).get('category', '?') if spec.is_file() else '?'
groups.setdefault((category, result['client'], result['arm']), []).append(result)
for (category, client, arm), runs in sorted(groups.items()):
median = lambda key: statistics.median(run[key] for run in runs)
lines.append(f'| {category} | {client} | {arm} | {len(runs)} | {sum(run["passed"] for run in runs) / len(runs):.0%} | '
f'{sum(run["first_try"] for run in runs) / len(runs):.0%} | {sum(run["rework_turns"] for run in runs)} | '
f'{median("seconds"):.0f} | {median("input_tokens"):.0f} | {median("output_tokens"):.0f} | {median("tool_calls"):.0f} | '
f'{sum(run["cost_usd"] for run in runs):.2f} | {sum(not run["workflow_violations"] for run in runs) / len(runs):.0%} |')
lines += ['', '## Workflow checks', '', '| client | arm | task | violations |', '|---|---|---|---|']
for result in sorted(results, key=lambda run: (run['client'], run['arm'], run['task'], run['repetition'])):
if result['workflow_violations']:
lines.append(f'| {result["client"]} | {result["arm"]} | {result["task"]} #{result["repetition"]} | {"; ".join(result["workflow_violations"])} |')
return '\n'.join(lines) + '\n'
def main():
parser = argparse.ArgumentParser(description=__doc__.splitlines()[0], formatter_class=argparse.RawDescriptionHelpFormatter, epilog=__doc__)
parser.add_argument('--clients', nargs='+', choices=('claude', 'codex'), default=['claude', 'codex'])
parser.add_argument('--arms', nargs='+', choices=('setup', 'baseline', 'setup-no-search'), default=['setup', 'baseline'],
help='setup-no-search is the setup with the semantic-search skill and CLI blocked (Claude only)')
parser.add_argument('--warm-index', action='store_true', help='start the QMD daemon and index the fixture before setup-arm sessions, outside the timing')
parser.add_argument('--tasks', nargs='+', help='task directory names or patterns such as 11-* (default: all)')
parser.add_argument('--repetitions', type=int, default=3)
parser.add_argument('--first-repetition', type=int, default=1, help='number of the first repetition, to rerun selected repetitions')
parser.add_argument('--rework', type=int, default=1, help='rework turns after a failed check')
parser.add_argument('--jobs', type=int, default=2)
parser.add_argument('--timeout', type=int, default=900, help='seconds per client turn')
parser.add_argument('--claude-model', default='sonnet')
parser.add_argument('--claude-effort', default='medium', choices=('low', 'medium', 'high', 'xhigh', 'max'))
parser.add_argument('--codex-model', help="default: the setup's configured model, pinned for both arms")
parser.add_argument('--codex-effort', help="default: the setup's configured reasoning effort, pinned for both arms")
parser.add_argument('--allow-unisolated', action='store_true', help='run even when the preflight finds the arms not comparable')
parser.add_argument('--codex-baseline-home', type=Path, default=Path.home() / '.my-ai-configuration/benchmark/codex-home')
parser.add_argument('--out', type=Path, default=Path(tempfile.gettempdir()) / f'ai-config-ab-{time.strftime("%Y%m%d-%H%M%S")}')
parser.add_argument('--dry-run', action='store_true', help='list the runs without starting clients')
parser.add_argument('--keep-failed', action='store_true', help='copy failed work trees to <out>/failed')
parser.add_argument('--summarize', nargs='+', type=Path, metavar='RESULTS', help='only summarize results.jsonl files; a later file replaces runs of an earlier one')
args = parser.parse_args()
if args.summarize:
merged = {}
for path in args.summarize:
for line in path.read_text(encoding='utf-8').splitlines():
result = json.loads(line)
key = (result['client'], result['arm'], result['task'], result['repetition'])
if not result.get('error') or key not in merged:
merged[key] = result
print(summarize(list(merged.values())))
return 0
tasks = [path for path in sorted(TASKS.iterdir()) if path.is_dir() and (not args.tasks or any(fnmatch.fnmatch(path.name, pattern) for pattern in args.tasks))]
for client in args.clients:
if not shutil.which(client):
parser.error(f'{client} CLI unavailable')
if 'codex' in args.clients and 'baseline' in args.arms and not (args.codex_baseline_home / 'auth.json').is_file():
parser.error(f'Codex baseline needs a login: run CODEX_HOME="{args.codex_baseline_home}" codex login')
jobs = [(client, arm, task, repetition) for repetition in range(args.first_repetition, args.first_repetition + args.repetitions)
for task in tasks for client in args.clients for arm in args.arms if not (client == 'codex' and arm == 'setup-no-search')]
if 'codex' in args.clients and not (args.codex_model and args.codex_effort):
configured = codex_configured(clean_env(), Path.cwd())
args.codex_model = args.codex_model or configured.get('model')
args.codex_effort = args.codex_effort or configured.get('model_reasoning_effort') or 'medium'
if not args.codex_model:
parser.error('the setup configures no Codex model; pass --codex-model')
provenance, problems = preflight(args, args.clients, args.arms)
args.out.mkdir(parents=True, exist_ok=True)
(args.out / 'provenance.json').write_text(json.dumps({'provenance': provenance, 'problems': problems}, indent=2), encoding='utf-8')
for key, data in provenance.items():
print(f'{key}: model={data["model"]} effort={data["effort"]} ' + ' '.join(f'{name}={value}' for name, value in data.items()
if name in ('skills_by_source', 'skills_by_scope', 'plugins', 'mcp_servers')))
for problem in problems:
print(f'NOT COMPARABLE: {problem}')
if problems and not args.allow_unisolated:
return 2
print(f'{len(jobs)} runs -> {args.out}')
if args.dry_run:
for client, arm, task, repetition in jobs:
print(f' {client} {arm} {task.name} #{repetition}')
return 0
args.out.mkdir(parents=True, exist_ok=True)
results, lock = [], threading.Lock()
def record(job):
result = run_one(job, args)
with lock:
results.append(result)
with open(args.out / 'results.jsonl', 'a', encoding='utf-8') as stream:
stream.write(json.dumps(result) + '\n')
print(f'[{len(results)}/{len(jobs)}] {result["client"]} {result["arm"]} {result["task"]} #{result["repetition"]}: '
f'{"PASS" if result["passed"] else "FAIL"} {result["seconds"]}s {result["tool_calls"]} tools', flush=True)
with ThreadPoolExecutor(max_workers=args.jobs) as pool:
list(pool.map(record, jobs))
(args.out / 'summary.md').write_text(summarize(results), encoding='utf-8')
print(summarize(results))
return 0
if __name__ == '__main__':
sys.exit(main())
+156
View File
@@ -0,0 +1,156 @@
"""Report the context the installed clients actually load, as the clients report it.
Complements the byte-based prompt budget gate: Claude's own `/context` and `/skill-doctor`
output and its init event, and Codex's `debug prompt-input`. No model request is made.
With --check, fail when an installed skill is missing from the client listing or is listed
without description context (for example because the client's skill budget dropped it).
"""
import argparse
import json
import os
from pathlib import Path
import queue
import re
import shutil
import subprocess
import sys
import tempfile
import threading
import tomllib
TIMEOUT = 180
def kill_tree(process):
if os.name == 'nt':
subprocess.run(['taskkill', '/T', '/F', '/PID', str(process.pid)], capture_output=True, timeout=30)
else:
process.kill()
process.wait(timeout=30)
def clean_env():
return {key: value for key, value in os.environ.items() if not key.startswith(('BUN_INSPECT', 'CLAUDECODE', 'CLAUDE_CODE_ENTRYPOINT'))}
def skill_names(root):
names = set()
for path in root.rglob('SKILL.md') if root.is_dir() else []:
match = re.search(r'(?m)^name:\s*"?([^"\r\n]+?)"?\s*$', path.read_text(encoding='utf-8-sig', errors='replace'))
if match:
names.add(match.group(1))
return names
def tokens(text):
# Claude prints "< 20" for small nonzero counts; count it as its upper bound.
text = text.strip().lstrip('~<').strip()
if text in ('', '-'):
return 0
return round(float(text[:-1]) * 1000) if text.endswith('k') else round(float(text))
def table_rows(markdown, heading):
section = re.search(rf'(?ms)^### {re.escape(heading)}\s*$(.*?)(?=^### |\Z)', markdown)
rows = []
for line in (section.group(1) if section else '').splitlines():
cells = [cell.strip() for cell in line.strip().strip('|').split('|')]
if line.startswith('|') and len(cells) >= 2 and not set(cells[0]) <= set('-') and cells[0] not in ('Category', 'Skill', 'Agent Type', 'Type', 'Tool'):
rows.append(cells)
return rows
def claude_print(claude, work, prompt, extra=()):
result = subprocess.run([claude, '-p', prompt, '--output-format', 'json', *extra], cwd=work, env=clean_env(),
capture_output=True, text=True, encoding='utf-8', timeout=TIMEOUT)
return json.loads(result.stdout).get('result', '')
def claude_init(claude, work, extra=()):
process = subprocess.Popen([claude, '-p', 'context probe', '--output-format', 'stream-json', '--verbose', *extra], cwd=work,
env=clean_env(), stdin=subprocess.DEVNULL, stdout=subprocess.PIPE, stderr=subprocess.DEVNULL,
text=True, encoding='utf-8')
lines = queue.Queue()
threading.Thread(target=lambda: [lines.put(line) for line in process.stdout], daemon=True).start()
try:
while True:
event = json.loads(lines.get(timeout=TIMEOUT))
if event.get('subtype') == 'init':
return event
finally:
kill_tree(process)
def measure_claude(home, work):
claude = shutil.which('claude')
if not claude:
return {'available': False}
context = claude_print(claude, work, '/context')
doctor = claude_print(claude, work, '/skill-doctor')
init = claude_init(claude, work)
listed = {row[0]: tokens(row[2]) for row in table_rows(context, 'Skills') if len(row) >= 3}
doctor_context = {}
for line in doctor.splitlines():
cells = line.split()
if len(cells) >= 3 and re.fullmatch(r'~?\d+(\.\d+)?k?|-', cells[2]):
doctor_context[cells[0]] = tokens(cells[2])
installed = skill_names(home / '.claude/skills')
return {
'available': True,
'categories': {row[0]: tokens(row[1]) for row in table_rows(context, 'Estimated usage by category')},
'plugins': sorted(plugin.get('name', str(plugin)) if isinstance(plugin, dict) else str(plugin) for plugin in init.get('plugins', [])),
'agents': len(init.get('agents', [])),
'mcp_servers': len(init.get('mcp_servers', [])),
'skills_listed': len(listed),
'installed_skills_missing': sorted(installed - set(listed)),
'skills_without_context': sorted(name for name, value in {**listed, **doctor_context}.items() if value == 0),
}
def measure_codex(home, work):
codex = shutil.which('codex')
if not codex:
return {'available': False}
result = subprocess.run([codex, 'debug', 'prompt-input', 'context probe'], cwd=work, env=clean_env(),
capture_output=True, text=True, encoding='utf-8', timeout=TIMEOUT)
prompt = result.stdout
listed = set(re.findall(r'(?m)^- ([^:\n]+?): .+?\(file: ', '\n'.join(
part.get('text', '') for item in json.loads(prompt or '[]') for part in item.get('content', []) if isinstance(part, dict))))
config_path = home / '.codex/config.toml'
config = tomllib.loads(config_path.read_text(encoding='utf-8-sig')) if config_path.is_file() else {}
installed = skill_names(home / '.agents/skills')
return {
'available': True,
'prompt_input_tokens_estimate': len(prompt.encode('utf-8')) // 4,
'plugins': sorted(name for name, value in config.get('plugins', {}).items() if isinstance(value, dict) and value.get('enabled', True)),
'skills_listed': len(listed),
'installed_skills_missing': sorted(installed - listed),
}
def main():
parser = argparse.ArgumentParser(description=__doc__.splitlines()[0])
parser.add_argument('--home', type=Path, default=Path.home())
parser.add_argument('--json', action='store_true')
parser.add_argument('--check', action='store_true')
args = parser.parse_args()
with tempfile.TemporaryDirectory(prefix='ai-config-context-', ignore_cleanup_errors=True) as directory:
subprocess.run(['git', 'init', '-q'], cwd=directory, check=True, timeout=60)
report = {'claude': measure_claude(args.home, directory), 'codex': measure_codex(args.home, directory)}
if args.json:
print(json.dumps(report, indent=2))
else:
for client, data in report.items():
if not data['available']:
print(f'{client}: CLI unavailable')
continue
print(f'{client}: {data["skills_listed"]} skills listed, plugins: {", ".join(data["plugins"]) or "none"}')
for key, value in data.items():
if key not in ('available', 'plugins', 'skills_listed'):
print(f' {key}: {value}')
problems = [name for data in report.values() if data['available'] for name in data['installed_skills_missing'] + data.get('skills_without_context', [])]
return 1 if args.check and problems else 0
if __name__ == '__main__':
sys.exit(main())
Whitespace-only changes.
@@ -0,0 +1,16 @@
import unittest
from pathlib import Path
from app import client, config
class Hidden(unittest.TestCase):
def test_default(self):
self.assertEqual(config.DEFAULT_TIMEOUT, 60)
self.assertEqual(client.request('x'), 60)
self.assertEqual(client.request('x', 5), 5)
def test_docs(self):
for path in ('README.md', 'app/client.py'):
text = Path(path).read_text()
self.assertIn('60 seconds', text)
self.assertNotIn('30 seconds', text)
@@ -0,0 +1,3 @@
# Client
Requests time out after 30 seconds unless a timeout is passed.
Whitespace-only changes.
@@ -0,0 +1,6 @@
from app.config import DEFAULT_TIMEOUT
def request(url, timeout=None):
"""Return the effective timeout in seconds; defaults to DEFAULT_TIMEOUT (30 seconds)."""
return timeout if timeout is not None else DEFAULT_TIMEOUT
@@ -0,0 +1 @@
DEFAULT_TIMEOUT = 30
@@ -0,0 +1,15 @@
{
"category": "small change",
"prompt": "Change the default request timeout from 30 to 60 seconds.",
"workflow": {
"kind": "small change without planning ceremony",
"forbid_skills": [
"superpowers:brainstorming",
"superpowers:writing-plans",
"superpowers:subagent-driven-development",
"superpowers:executing-plans"
],
"max_agents": 0,
"max_tool_calls": 15
}
}
Whitespace-only changes.
@@ -0,0 +1,11 @@
import unittest
from app.pagination import paginate
class Hidden(unittest.TestCase):
def test_last_page(self):
self.assertEqual(paginate(list(range(10)), 4, 3), [9])
self.assertEqual(paginate(list(range(9)), 3, 3), [6, 7, 8])
def test_out_of_range(self):
self.assertEqual(paginate(list(range(3)), 5, 3), [])
Whitespace-only changes.
@@ -0,0 +1,5 @@
def paginate(items, page, size):
"""Return the 1-based page of items with the given page size."""
start = (page - 1) * size
end = min(start + size, len(items) - 1)
return items[start:end]
Whitespace-only changes.
@@ -0,0 +1,7 @@
import unittest
from app.pagination import paginate
class PaginationTests(unittest.TestCase):
def test_first_page(self):
self.assertEqual(paginate(list(range(10)), 1, 3), [0, 1, 2])
@@ -0,0 +1,15 @@
{
"category": "small change",
"prompt": "Users report that the last item is missing on the final page returned by paginate(). Fix the bug.",
"workflow": {
"kind": "bugfix with targeted verification",
"forbid_skills": [
"superpowers:brainstorming",
"superpowers:writing-plans",
"superpowers:subagent-driven-development",
"superpowers:executing-plans"
],
"max_agents": 0,
"require_command": "test_pagination|pagination"
}
}
Whitespace-only changes.
@@ -0,0 +1,17 @@
import unittest
from app.parsers.csv_parser import parse_csv
from app.parsers.ini_parser import parse_ini
from app.parsers.json_parser import parse_json_lines
class Hidden(unittest.TestCase):
def test_csv(self):
self.assertEqual(parse_csv('a, b\n1, "x,y"\n\n2,3\n'), [{'a': '1', 'b': 'x,y'}, {'a': '2', 'b': '3'}])
def test_json(self):
self.assertEqual(parse_json_lines('{"a": 1}\n\n[2]\n'), [{'a': 1}, [2]])
with self.assertRaisesRegex(ValueError, '2'):
parse_json_lines('{}\n{bad\n')
def test_ini(self):
self.assertEqual(parse_ini('top = 1\n; c\n[s]\n# c\n k = v \n'), {'': {'top': '1'}, 's': {'k': 'v'}})
Whitespace-only changes.
@@ -0,0 +1,6 @@
def parse_csv(text):
"""Parse comma-separated text with a header row into a list of dicts.
Strip whitespace around cells, skip blank lines, and support double-quoted cells containing commas.
"""
raise NotImplementedError
@@ -0,0 +1,6 @@
def parse_ini(text):
"""Parse INI text into {section: {key: value}}.
Ignore lines starting with ; or #, strip whitespace, keep keys before the first section under "".
"""
raise NotImplementedError
@@ -0,0 +1,6 @@
def parse_json_lines(text):
"""Parse JSON Lines text into a list of objects.
Skip blank lines. Raise ValueError naming the 1-based line number for invalid JSON.
"""
raise NotImplementedError
@@ -0,0 +1,9 @@
{
"category": "larger implementation",
"prompt": "Implement the three independent parsers in app/parsers (csv_parser, json_parser, ini_parser) according to their docstrings, and add unit tests for each. They share no code.",
"workflow": {
"kind": "larger change with justified delegation",
"min_agents": 1,
"max_agents": 3
}
}
Whitespace-only changes.
@@ -0,0 +1,16 @@
import sqlite3
import unittest
from app.users import find_user
class Hidden(unittest.TestCase):
def setUp(self):
self.conn = sqlite3.connect(':memory:')
self.conn.execute('CREATE TABLE users (id INTEGER, name TEXT)')
self.conn.executemany('INSERT INTO users VALUES (?, ?)', [(1, "O'Brien"), (2, 'admin')])
def test_apostrophe(self):
self.assertEqual(find_user(self.conn, "O'Brien"), (1, "O'Brien"))
def test_injection(self):
self.assertIsNone(find_user(self.conn, "x' OR '1'='1"))
Whitespace-only changes.
@@ -0,0 +1,3 @@
def find_user(conn, name):
"""Return (id, name) for the user with the given name, or None."""
return conn.execute(f"SELECT id, name FROM users WHERE name = '{name}'").fetchone()
@@ -0,0 +1,7 @@
{
"category": "small change",
"prompt": "find_user() fails for user names that contain an apostrophe, such as O'Brien. Fix it.",
"workflow": {
"kind": "security-relevant bugfix"
}
}
Whitespace-only changes.
@@ -0,0 +1,31 @@
import shutil
import subprocess
import sys
import tempfile
import unittest
from pathlib import Path
MUTANTS = [
('.rstrip("-")', ''),
('.lower()', ''),
('"ascii", "ignore"', '"ascii", "replace"'),
]
def run_tests(root):
return subprocess.run([sys.executable, '-m', 'unittest', 'discover', '-s', 'tests', '-t', '.'], cwd=root, capture_output=True, text=True, timeout=120)
class Hidden(unittest.TestCase):
def test_tests_pass(self):
result = run_tests('.')
self.assertEqual(result.returncode, 0, result.stderr[-2000:])
self.assertRegex(result.stderr, r'Ran ([3-9]|\d\d+) tests')
def test_tests_catch_mutants(self):
source = Path('app/slug.py').read_text()
for old, new in MUTANTS:
with self.subTest(old), tempfile.TemporaryDirectory() as directory:
shutil.copytree('.', directory, dirs_exist_ok=True, ignore=shutil.ignore_patterns('.git', 'bench_hidden'))
Path(directory, 'app/slug.py').write_text(source.replace(old, new, 1))
self.assertNotEqual(run_tests(directory).returncode, 0, f'tests miss mutant {old!r}')
Whitespace-only changes.
@@ -0,0 +1,9 @@
import re
import unicodedata
def slugify(text, max_length=50):
"""Lowercase ASCII slug with single hyphens, trimmed to max_length without a trailing hyphen."""
text = unicodedata.normalize("NFKD", text).encode("ascii", "ignore").decode()
text = re.sub(r"[^a-zA-Z0-9]+", "-", text).strip("-").lower()
return text[:max_length].rstrip("-")
Whitespace-only changes.
@@ -0,0 +1,7 @@
{
"category": "larger implementation",
"prompt": "Add unittest-based unit tests for app/slug.py under tests/ that cover its edge cases.",
"workflow": {
"kind": "test writing"
}
}
Whitespace-only changes.
@@ -0,0 +1,16 @@
import unittest
from pathlib import Path
from app.report import cost_report, sales_report
ROWS = [(' widgets ', 1234.5), ('gadgets', 99)]
EXPECTED = 'Widgets 1,234.50\nGadgets 99.00\nTotal 1,333.50'
class Hidden(unittest.TestCase):
def test_output(self):
self.assertEqual(sales_report(ROWS), EXPECTED)
self.assertEqual(cost_report(ROWS), EXPECTED)
self.assertEqual(sales_report([]), f"{'Total':<20}{0:>12,.2f}")
def test_deduplicated(self):
self.assertEqual(Path('app/report.py').read_text().count('.title()'), 1)
Whitespace-only changes.
@@ -0,0 +1,20 @@
def sales_report(rows):
lines = []
for name, amount in rows:
label = name.strip().title()
value = f"{amount:,.2f}"
lines.append(f"{label:<20}{value:>12}")
total = sum(amount for _, amount in rows)
lines.append(f"{'Total':<20}{total:>12,.2f}")
return "\n".join(lines)
def cost_report(rows):
lines = []
for name, amount in rows:
label = name.strip().title()
value = f"{amount:,.2f}"
lines.append(f"{label:<20}{value:>12}")
total = sum(amount for _, amount in rows)
lines.append(f"{'Total':<20}{total:>12,.2f}")
return "\n".join(lines)
@@ -0,0 +1,7 @@
{
"category": "larger implementation",
"prompt": "Remove the duplicated formatting logic in app/report.py without changing its output.",
"workflow": {
"kind": "behavior-preserving refactor"
}
}
Whitespace-only changes.
@@ -0,0 +1,20 @@
import json
import tempfile
import unittest
from pathlib import Path
from app.settings_store import save_settings
class Hidden(unittest.TestCase):
def test_unknown_keys_survive(self):
with tempfile.TemporaryDirectory() as directory:
path = Path(directory) / 'settings.json'
path.write_text(json.dumps({'theme': 'dark', 'plugins': {'a': True}, 'x': 1}))
save_settings(path, {'language': 'de'})
self.assertEqual(json.loads(path.read_text()), {'theme': 'dark', 'plugins': {'a': True}, 'x': 1, 'language': 'de'})
def test_new_file(self):
with tempfile.TemporaryDirectory() as directory:
path = Path(directory) / 'settings.json'
save_settings(path, {'theme': 'light'})
self.assertEqual(json.loads(path.read_text()), {'theme': 'light'})
@@ -0,0 +1,15 @@
import json
KNOWN = ("theme", "language")
def save_settings(path, updates):
"""Apply updates to the JSON settings file at path."""
try:
with open(path, encoding="utf-8") as stream:
current = json.load(stream)
except FileNotFoundError:
current = {}
merged = {key: updates.get(key, current.get(key)) for key in KNOWN if key in updates or key in current}
with open(path, "w", encoding="utf-8") as stream:
json.dump(merged, stream, indent=2)
@@ -0,0 +1,7 @@
{
"category": "small change",
"prompt": "save_settings() loses keys it does not know about when it updates the settings file. Fix it so unknown keys survive.",
"workflow": {
"kind": "data-preserving bugfix"
}
}
Whitespace-only changes.
@@ -0,0 +1,15 @@
import inspect
import unittest
from pathlib import Path
from app import api, cli
class Hidden(unittest.TestCase):
def test_signature(self):
self.assertEqual(list(inspect.signature(api.fetch).parameters), ['url', 'max_retries'])
self.assertEqual(cli.main('u'), 2)
def test_docs(self):
text = Path('README.md').read_text()
self.assertIn('max_retries', text)
self.assertNotRegex(text, r'(?<![\w])retries(?=[=`])')
@@ -0,0 +1,3 @@
# API
`fetch(url, retries=3)` retries a request up to `retries` times.
Whitespace-only changes.
@@ -0,0 +1,3 @@
def fetch(url, retries=3):
"""Fetch url, retrying up to retries times. Returns the attempts used."""
return min(retries, 3) if url else 0
@@ -0,0 +1,5 @@
from app.api import fetch
def main(url):
return fetch(url, retries=2)
@@ -0,0 +1,7 @@
{
"category": "small change",
"prompt": "Rename the retries parameter of app.api.fetch to max_retries.",
"workflow": {
"kind": "API change with directly affected documentation"
}
}
Whitespace-only changes.
@@ -0,0 +1,26 @@
import os
import tempfile
import unittest
from pathlib import Path
from app.files import read_upload
class Hidden(unittest.TestCase):
def setUp(self):
self.directory = tempfile.TemporaryDirectory()
root = Path(self.directory.name)
(root / 'uploads/sub').mkdir(parents=True)
(root / 'uploads/sub/a.txt').write_bytes(b'ok')
(root / 'secret.txt').write_bytes(b'secret')
self.base = str(root / 'uploads')
def tearDown(self):
self.directory.cleanup()
def test_nested(self):
self.assertEqual(read_upload(self.base, 'sub/a.txt'), b'ok')
def test_traversal(self):
for name in ('../secret.txt', 'sub/../../secret.txt', os.path.join(os.path.dirname(self.base), 'secret.txt')):
with self.subTest(name), self.assertRaises((ValueError, PermissionError, FileNotFoundError)):
read_upload(self.base, name)
Whitespace-only changes.
@@ -0,0 +1,7 @@
import os
def read_upload(base, name):
"""Return the bytes of the uploaded file name below the base directory."""
with open(os.path.join(base, name), "rb") as stream:
return stream.read()
@@ -0,0 +1,7 @@
{
"category": "small change",
"prompt": "Make read_upload() safe against path traversal. Legitimate names in nested folders must keep working.",
"workflow": {
"kind": "security hardening"
}
}
Whitespace-only changes.
@@ -0,0 +1,16 @@
import time
import unittest
from app.dedupe import dedupe
class Hidden(unittest.TestCase):
def test_behavior(self):
self.assertEqual(dedupe([3, 1, 3, 2, 1]), [3, 1, 2])
self.assertEqual(dedupe([]), [])
self.assertEqual(dedupe(['a', 'b', 'a']), ['a', 'b'])
def test_fast(self):
items = list(range(100000)) * 2
start = time.perf_counter()
self.assertEqual(len(dedupe(items)), 100000)
self.assertLess(time.perf_counter() - start, 1.0)
Whitespace-only changes.
@@ -0,0 +1,7 @@
def dedupe(items):
"""Return items without duplicates, keeping the first occurrence of each."""
result = []
for item in items:
if item not in result:
result.append(item)
return result
@@ -0,0 +1,7 @@
{
"category": "small change",
"prompt": "dedupe() is far too slow for 100,000 items. Make it fast while keeping its behavior and the order of first occurrences.",
"workflow": {
"kind": "performance fix"
}
}
Whitespace-only changes.
@@ -0,0 +1,14 @@
import unittest
from datetime import date
from app.accounts import Account
from app.ledger.archive import render_period_summary
class Hidden(unittest.TestCase):
def test_expired_evaluation_blocked(self):
with self.assertRaises(PermissionError):
render_period_summary(Account('evaluation', date(2026, 1, 1)), '2026-01', today=date(2026, 2, 1))
def test_running_evaluation_and_paid_allowed(self):
self.assertIsInstance(render_period_summary(Account('evaluation', date(2026, 3, 1)), '2026-01', today=date(2026, 2, 1)), bytes)
self.assertIsInstance(render_period_summary(Account('paid'), '2026-01', today=date(2026, 2, 1)), bytes)
@@ -0,0 +1,9 @@
from dataclasses import dataclass, field
from datetime import date
@dataclass
class Account:
tier: str # "evaluation" or "paid"
evaluation_until: date | None = None
entries: list = field(default_factory=list)
@@ -0,0 +1,8 @@
from datetime import date
def render_period_summary(account, period, today=None):
"""Build the period summary document for an account."""
today = today or date.today()
lines = [f"{entry.label}: {entry.amount:.2f}" for entry in account.entries if entry.period == period]
return "\n".join(lines).encode()
@@ -0,0 +1,10 @@
{
"category": "search",
"prompt": "Customers whose free trial has ended can still download their monthly statements. Block that by raising PermissionError, and keep it working for paying customers and for customers whose trial is still running.",
"generate": {
"filler_modules": 250
},
"workflow": {
"kind": "concept search in a large repository"
}
}
Whitespace-only changes.
@@ -0,0 +1,32 @@
import unittest
from app.transport.courier import dispatch
class Channel:
def __init__(self, failures, error=ConnectionResetError):
self.failures, self.error, self.calls = failures, error, 0
def send(self, blob):
self.calls += 1
if self.calls <= self.failures:
raise self.error('flaky')
return 'receipt'
class Hidden(unittest.TestCase):
def test_retries_transient(self):
channel = Channel(2)
self.assertEqual(dispatch(b'x', channel), 'receipt')
self.assertEqual(channel.calls, 3)
def test_gives_up_after_three(self):
channel = Channel(5)
with self.assertRaises(ConnectionResetError):
dispatch(b'x', channel)
self.assertEqual(channel.calls, 3)
def test_no_retry_for_other_errors(self):
channel = Channel(1, ValueError)
with self.assertRaises(ValueError):
dispatch(b'x', channel)
self.assertEqual(channel.calls, 1)
Whitespace-only changes.
@@ -0,0 +1,3 @@
def dispatch(blob, channel):
"""Hand a blob to the channel and return the receipt."""
return channel.send(blob)
@@ -0,0 +1,10 @@
{
"category": "search",
"prompt": "Fix the upload code: uploads that fail with a temporary network error are never retried. They should make at most three attempts in total before giving up with the last error; other errors must not be retried.",
"generate": {
"filler_modules": 250
},
"workflow": {
"kind": "concept search in a large repository"
}
}
Whitespace-only changes.
@@ -0,0 +1,10 @@
import unittest
from app.fin.tally import consolidate
class Hidden(unittest.TestCase):
def test_half_up(self):
self.assertEqual(float(consolidate([1.005])), 1.01)
self.assertEqual(float(consolidate([2.675])), 2.68)
self.assertEqual(float(consolidate([1.0, 0.004])), 1.0)
self.assertEqual(float(consolidate([0.1, 0.2])), 0.3)
Loaded 100 of 381 files, more files were not shown because too many files have changed in this diff. Show more