-
GitHub CLI access in containers— Done.~/.config/ghis mounted from the host at start time (when present), same pattern as SSH agent and git config.ghwas already in the base image and all required GitHub domains were already in the base firewall allowlist. -
Smoother session startup— Done.codeandshellnow auto-init and auto-build on first run; single command for both fresh and existing projects. -
Mobile dev environment— Done. Added--lang android: OpenJDK 21 + Android SDK cmdline-tools + platform-tools + build-tools 35 + API 35 platform. -
Better host tool integration — Integrate with tmux, emacs, etc. so users don't have to manually set up sessions before starting work (related to item 1).
4a. Bump base image to Alpine 3.24 — Done. Alpine 3.24 released 2026-06-09; ships musl 1.2.6 which unblocks the native Claude installer.
4b. Switch to native Claude installer — Done. Replaced npm install workaround with curl -fsSL https://claude.ai/install.sh | bash. Requires musl 1.2.6+ (Alpine 3.24). Added downloads.claude.ai to firewall allowlist for auto-updates.
- Improve security — Possibly move firewall rules to the host instead of inside the container; explore best approach.
5a. Faster solidity image builds — Done. Switched from cargo install (Rust compile from source) to foundryup (pre-built binaries). Eliminates 10–20 min compile time and build fragility.
-
Web vulnerability checking commands— Done. Added five web security skills (/vuln-scan,/sqli-deep,/authz-review,/secrets-audit,/depcheck) toskills/. -
Migrate commands to skills— Done. Moved all commands toskills/<name>/SKILL.mdformat; removedcommands/directory; updated README and CLAUDE.md. -
Pre-audit improvement— Done./pre-auditnow detects missingnode_moduleswhenpackage.jsonis present and stops with an actionable error. -
Trim base image packages— Done. Moved packages only needed by specific languages out of the shared base image and into the relevantlang_packages_*/postinstall entries:jqmoved tosolidityandterraform(both need it forwget | jq -rversion lookups);unzipmoved toterraformandandroid(both unzip downloaded archives);nodejs/npmmoved tolang_packages_node(already duplicated there, base copy was redundant) — note left in script that they may need to move back to base if we start relying on MCP servers (commonly launched vianpxregardless of--lang). Dropped entirely as pure convenience tools (not required by any build/git/firewall operation, or by Claude Code itself — confirmedfd/fzfaren't shelled out to internally, unlike ripgrep which has aUSE_BUILTIN_RIPGREPoverride):bash-completion,mandoc,man-pages,less,htop,tree,procps,fd,fzf. Can be added back with a one-offapk addinside the container if needed interactively. Not pursuing backend-specific package scoping (e.g.gcompat/libgcc/libstdc++only needed by theclaudebackend) — no interest in backend-specific containers right now. -
Opt out of nonessential Claude Code traffic/auto-update— Done. AddedCLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC=1andDISABLE_AUTOUPDATER=1to the generated Dockerfile, per official devcontainer guidance (code.claude.com/docs/en/devcontainer). Containers are rebuilt regularly, so updates happening at image-build time (rather than via background checks) is intended; manualclaude updateinside a running container still works. Note: disabling nonessential traffic also disables feature-flag evaluation, so Remote Control and other flag-gated features are unavailable in-container — accepted tradeoff. Considered but declined: pinning the Claude Code CLI version itself (native installer always grabs latest; would require switching back to npm install to pin) and/etc/claude-code/managed-settings.jsonfor org policy — both left as-is, not worth pursuing currently. -
Audit skill fixes— Done. Merged 2026-10-09 (PR #1,39d104c). The final PDF was hard to read and much too long (e.g. a 57-page report with only a few Informational findings).Phase 1 — Reorder the PDF (
skills/audit-report/SKILL.md) — Done, signed off 2026-10-09 (2295675).- New order for the combined document:
- Report header (generated): Date, Auditor, Repository, Commit, Scope, taken from the per-file reports. If the reports disagree on a value (e.g. commit), list every distinct value.
- Findings summary (generated): a severity count table from the checklist's
**Total:**line, followed by one combined findings table across all reports (ID, Severity, Title, Contract). Include the report filename in the ID, or renumber findings, so IDs don't collide (every per-file report starts at F-01). - Round-over-round comparison (only if
audit/round-*/exists), same as now. - Detailed findings: each
audit-*.md, with its repeated Date/Auditor/Repository/Commit header block removed in the combined document only (source files untouched). - Appendices: ToB maturity, ToB prep, then prior rounds.
- Drop
AUDIT-CHECKLIST.mdfrom the PDF entirely, both for the current round and in prior-round appendices. It is still read for the completeness check and the totals. - Update the Rules section ("checklist first" no longer applies).
Phase 2 — Make reports shorter (
skills/audit/SKILL.md,skills/audit-report/SKILL.md) — Done, signed off 2026-10-09.- Sample: Safe-gaurd rerun (2026-10-08, 9 reports, 2 Low + 8 Informational). The
audit-*.mdfiles total 64 KB, and the ToB appendices add another 27 KB. Where the 64 KB goes:- Executive Summary: 38%. Mostly per-file "what was verified ✓" tables, plus descriptions of what each contract does.
- Informational findings: 29%. Each has a full description, PoC, fix and Foundry regression test (even "delete this unused file" got a test).
- Low findings: 18%.
- Per-file
## Summarywith "Top 3 recommendations": 8%. It pads to three even with a single Informational finding.
- Changes:
- Scale detail to severity:
- Critical/High: full detail, same as now (description, step-by-step PoC, fix with code, Foundry regression test).
- Medium: description, short PoC, fix with code. Foundry test only if the PoC is not obvious.
- Low: description, a short fix (code only if a few lines), PoC only as brief numbered steps when needed to show the issue is real. No regression test.
- Informational: only a row in an
## Informationaltable (ID, location, issue, suggestion). No separate section.
- Executive summary: overall risk plus 2–4 sentences, then a short "Areas verified" list (a few one-line bullets) instead of the per-check verification table. No description of what the contract does.
- Drop the per-file
## Summarysection (totals and Top 3 recommendations). It repeats the Findings Summary table. - Files with no findings, or declarations only (interfaces): header, one-line result, done.
- Keep the
## Findings Summarytable format unchanged so/audit-reportand the checklist update keep working.
- Scale detail to severity:
- ToB output (
skills/audit-report/SKILL.md): the rerun (2026-10-09) cut the reports to 22.6 KB (−65%), but the ToB plugin output grew from 27 KB to 67 KB, so the PDF stayed about the same size. The plugins' length and headings vary between runs./audit-reportnow includes only keyword-matched excerpts: maturity executive summary, scorecard and roadmap; prep static analysis, checklist and unavailable tools. Prior rounds get only the maturity scorecard. The full files stay inaudit/. On the rerun this is 15 KB of 67 KB, so about 40 KB total goes into the PDF, down from 90 KB.
Phase 3 — Docs
- Update README.md and CLAUDE.md wherever they describe the audit report layout.
- Reinstall the skills (
cp -r skills/audit skills/audit-report ~/.claude/skills/) and test on a real audit directory if one is available.
- New order for the combined document:
-
Install Slither in the— Done. Slither 0.11.6 with all transitive dependencies pinned, installed viasoliditylangpipx install --global; regenerate pins withmisc/slither-constraints.sh. Slither is useful for contract analysis, and/pre-audit's ToB prep step already looks for it (in the Safe-gaurd sample,tob-prep.mdhad to substituteforge lint). Installslither-analyzerat a pinned version (probably via pip/pipx, which needspython3/py3-pipadded tolang_packages_solidity). Check that it works with the staticsolcbinary already installed, and add any PyPI domains it needs to the solidity firewall allowlist.allpicks it up through solidity.Findings
- Latest release is
slither-analyzer0.11.6 (2026-07-28). Requires Python >= 3.10 and supports 3.14. - Dependencies: crytic-compile (
<0.5), web3 7.x, eth-abi/eth-typing/eth-utils, pycryptodome, prettytable. crytic-compile pulls insolc-select, which installs its ownsolcshim. - Alpine's Python is externally managed (PEP 668), so a plain
pip installfails. Install into an isolated environment instead. - The image is built without the firewall (it is applied at
start), so PyPI only has to be reachable at build time. At runtime Slither callsforge/solclocally. It only goes online ifsolc-selectdownloads a compiler, and that usesbinaries.soliditylang.org, which is already allowed. So no new firewall domains are expected.
Decision (2026-10-12): pin Slither and all its transitive dependencies (reproducibility over convenience; regenerating on each bump is acceptable).
Phase 1 — Install (
ai-devcontainer.sh,misc/)- Add
pipx(pulls inpython3) tolang_packages_solidity. - The build context is the project's
.devcontainer/, not this repo, so a constraints file next to the script won't reach the build. Instead, keep the pinned list (pip freezeoutput,name==versionper line) in aSLITHER_CONSTRAINTSvariable inai-devcontainer.sh, with the Slither version at the top. The generated Dockerfile writes it to/tmp/slither-constraints.txtand runsPIP_CONSTRAINT=/tmp/slither-constraints.txt pipx install slither-analyzer==<ver>. The pins are also visible in the committed Dockerfile. - Add
misc/slither-constraints.sh <version>to regenerate the list. It runs a throwawayalpine:3.24container with$AI_DEVCONTAINER_ENGINE(default podman), installs Slither via pipx, and prints the venv'spip freeze. Run it on the host (this dev container has no engine or PyPI access) and paste the output into the script. Same Alpine release and Python as the image, so the pins resolve to the same wheels/builds. - Add a
_lang_postinstall_slitherstep and add it tolang_postinstall_soliditysoallgets it too. - Not doing hash pinning (
--require-hashes): musl/source builds make per-file hashes brittle. Version pins only. - Make sure the static
/usr/local/bin/solcwins oversolc-select's shim in~/.local/bin(check PATH order). Otherwisesolcwould start pointing at a solc-select-managed version with no compiler installed. (Resolved: not exposed by pipx, see status below.) - Some transitive dependencies may have no musl wheels and need a C build (e.g.
ckzg,bitarray). If the build fails, addbuild-base python3-devonly for the install step, or permanently if that's simpler. - Test (on the host): run
misc/slither-constraints.sh 0.11.6and paste the result in, thenbuild --lang solidityon a scratch project, then inside the container runslither --version,solc --version(still the static binary), andslither .on a small Foundry project.
Phase 1 status (2026-10-12) — Done, signed off 2026-10-12.
- Pins generated in this container (Alpine 3.24.2, Python 3.14.8): 47 packages, all with musl wheels, so no
build-base/python3-devis needed. - Changed from the plan: install with
pipx install --global(venv in/opt/pipx, commands in/usr/local/bin) instead of per-user~/.local/bin. The opencode backend's PATH doesn't include~/.local/bin. - The
solcshim is a non-issue. pipx only exposes Slither's own commands, sosolc-select'ssolcstays inside the venv. - Verified here: the generated RUN step installs cleanly,
slither --versionprints 0.11.6, the installed venv'spip freezematches the pins exactly, and the temp constraints file is removed.slitheron a real contract could not be tested here (nosolc, and the solc download hosts aren't allowlisted in abasecontainer). - Host test (2026-10-12):
--lang solidityimage builds;slither --version= 0.11.6;which solc=/usr/local/bin/solc(0.8.37);slither .on a freshforge initproject compiles through forge and reports 1 result (solc-version), as expected.
Phase 2 — Docs — Done, signed off 2026-10-12.
- README language table and
langs/usage text: mention Slither undersolidity. - README: how to bump Slither (run
misc/slither-constraints.sh, paste output, rebuild). - CLAUDE.md if needed. Mark this item done (and fold in the item 11 TODO update).
- Latest release is
-
Audit PDF content overflows the page— Done. Fixed 2026-10-12. Some content in the/audit-reportPDF runs past the page margins. Likely causes in the stylesheet (skills/audit-report/SKILL.mdStep 3):pre { overflow-x: auto; }scrolls on screen but just clips in print, so long code lines run off the page. Also, long unbroken inlinecode(paths, hashes, selectors) and wide tables (e.g. the 4-column Informational table) don't wrap. Possible fixes:pre { white-space: pre-wrap; overflow-wrap: anywhere; },code { overflow-wrap: anywhere; },table { table-layout: fixed; }withtd { overflow-wrap: anywhere; }, and an explicit@pagesize/margin. Find the overflowing pages in a real PDF first to confirm which of these it is.Findings (2026-10-12), from
audit/audit-report-20261012.pdf, a real 11-file report. No poppler in the container, so the page streams were inflated by hand and their drawing coordinates checked.- The page is 794px wide (A4). With weasyprint's default 75px margin and the body's
2empadding, the content box runs from x=104 to x=689 (585px). - On 9 pages, tables are drawn 652–885px wide. The worst reaches x=990, past the page edge, so its right-hand column is lost, not just clipped at the margin.
- Cause: unbreakable inline
codein cells (e.g.PermissionedLendingPool.sol:406-425,494-518in the Informational tables' Location column). Auto table layout won't shrink a column below its longest unbreakable word, so the whole table grows past the page. preis not a problem in this PDF. Highlighted blocks (e.g.```solidity) already wrap in print because of pandoc's highlighting CSS. An unlabelled```block with long lines would still clip, though.
Phase 1 — Stylesheet fix (
skills/audit-report/SKILL.mdStep 3)code { overflow-wrap: anywhere; }, and the same onth, td. Unlikebreak-word,anywherelowers the min-content width, so auto-layout tables can fit the page. Keep auto layout (nottable-layout: fixed), so the narrow ID/Severity columns stay narrow.pre: replaceoverflow-x: autowithwhite-space: pre-wrap; overflow-wrap: anywhere;(and the same onpre code), so unlabelled code blocks wrap rather than clip.- Add an explicit
@page { size: A4; margin: 2cm; }, and drop the screen-orientedmax-width: 900px; margin: 0 auto; padding: 2emfrombody. This gives back about 60px of width and makes the layout explicit rather than relying on weasyprint defaults. - Test (needs weasyprint: the host or a
soliditycontainer, since this container can't install it): regenerate the PDF from the sameaudit/files and confirm no table runs past the margin, and that the Informational tables are still readable. The stream-coordinate check used above can be repeated to verify: nore/Tmx beyond the right content edge.
Phase 1 status (2026-10-12) — Done, signed off 2026-10-12. Host test: the PDF was regenerated from the same
audit/files and looks fine by eye. The stream-coordinate check finds nothing past the content box (x 83.6–710.1, about 627px wide, up from 585px) on any of the 45 page streams, and nothing below the page bottom. Before the fix, tables reached x=990.Phase 2 — Docs — Done, signed off 2026-10-12.
- README
/audit-reportsection: notes the A4 layout and wrapping. CLAUDE.md needed no change (it doesn't describe the stylesheet). Item marked done.
- The page is 794px wide (A4). With weasyprint's default 75px margin and the body's
-
Brief audit report— Done. New/audit-briefskill, run by/full-auditafter/audit-report. Add a short PDF alongside the full/audit-reportPDF, for readers who only need the key results. It holds just the basic info table and the Critical, High, and Medium findings, and names the full report file. New/audit-briefskill, called by/full-auditafter/audit-report.Phase 1 —
/audit-briefskill (skills/audit-brief/SKILL.md)- Preconditions, same as
/audit-report: the checklist exists and is complete, and at least one current-roundaudit-*.mdexists. Also needs the full PDF: use the newestaudit/audit-report-*.pdf. If there is none, stop and tell the user to run/audit-reportfirst. If any current-roundaudit-*.mdis newer than that PDF, warn that the full report may be out of date and continue. - Output:
audit/audit-brief-<YYYYMMDD>.pdf. Title: "Smart Contract Audit Report (Brief)". - Contents, in order:
- Basic info table: the same header table as the full report (report date, audit date(s), auditor, repository, commit, scope, audit round), plus a Full report row naming the full PDF's filename (e.g.
audit-report-20261103.pdf). - A severity count table for Critical, High, and Medium only, from the checklist's
**Total:**line. - A combined findings table of the Critical/High/Medium findings only, with the same scope-prefixed IDs as the full report (
Vault F-01), so IDs match between the two PDFs. If there are none, writeNo Critical, High, or Medium findings.and skip item 4. - Each Critical/High/Medium finding's full write-up (the
### F-NN [SEVERITY] ...section, up to the next###/##), copied from its per-file report. Grouped by severity, then report filename, then ID. They go under a# Findingsheading, and each heading becomes## <scope> F-NN [SEVERITY] ...so it matches the table. - A closing note: Low and Informational findings, the executive summaries, round-over-round comparison, and appendices are in the full report,
audit/<full report filename>.
- Basic info table: the same header table as the full report (report date, audit date(s), auditor, repository, commit, scope, audit round), plus a Full report row naming the full PDF's filename (e.g.
- Leaves out: Low/Informational findings, per-file executive summaries, round comparison, prior rounds, ToB appendices.
- Same stylesheet as
/audit-report(copied into the skill; the two skills don't share files) and the same pandoc → weasyprint pipeline, success check, no-fallback rule, and temp-file cleanup (temp names/tmp/audit-brief.*so they don't collide). - Current round only.
- Also added: a one-line note under the info table saying the brief covers Critical–Medium only, naming the full report.
Phase 1 status (2026-11-03) — Done, signed off 2026-11-03.
- Test: run
/audit-briefagainst a realaudit/directory (needs weasyprint, so on the host or in asoliditycontainer), and check that the Full report row and the closing note name the right file, the IDs match the full PDF, and no Low/Informational findings appear.
Phase 2 — Wire into
/full-audit- New step after "Generate report": invoke
/audit-brief. - The final summary prints both PDF paths.
- If
/audit-reportfails, stop (as before). If/audit-brieffails, report the error but still print the summary, since the full PDF already exists.
Phase 2 status (2026-11-03) — Done, signed off 2026-11-03.
Phase 3 — Docs
- README: a
/audit-briefsection, an entry in the skill table, and the updated/full-auditdescription. - CLAUDE.md: add
/audit-briefto the smart contract audit skill list. Mark this item done.
Phase 3 status (2026-11-03) — Done, signed off 2026-11-03.
- Preconditions, same as