Commit graph

784 commits

Author SHA1 Message Date
b548126fb8 fix(halo): fix systemd description for llama 2026-05-07 14:40:18 +02:00
1aa98a8051 fix(opencode): require real shell timestamp in workflow summary
A workflow run wrote the timestamp as `2026-05-06T???:???:?? (session date)`
because the agent had no time-of-day source and inserted a placeholder.
Phase 9 now mandates capturing the timestamp from the shell at write
time via `date -Iseconds` and forbids placeholders — omit the field
rather than fabricate one.
2026-05-07 05:45:35 +02:00
5b5c59aa84 feat(opencode): mandate stub-first @make pre-pass for Rust integration TDD
Rust integration tests live in a separate test crate that imports from
lib.rs, so any test referencing not-yet-existing public API can only
RED at build time. The build error masks assertion diagnostics and
makes the RED state opaque — no stack trace, no left/right values.

For Rust tasks whose @test step writes an integration test against
public API that does not yet exist, the orchestrator now dispatches a
stub-first @make pass before @test runs:

1. @make adds the planned public API as todo!()-bodied stubs in
   lib.rs and any new src/<module>.rs. Signatures lifted verbatim
   from the Phase 5 task spec. Acceptance criterion is cargo check
   only — no test command runs.
2. @test writes the integration test, which now compiles and panics
   at todo!() with a stack trace — a clean MISSING_BEHAVIOR RED.
3. Phase 7 dispatches @make again to replace the todo!() bodies with
   real implementations. Two atomic commits per task: scaffold then
   implement.

Phase 5's Rust test-path guidance now flags the two-dispatch
requirement up front. test.md's Rust failure-classification hints
recognize todo!() / unimplemented!() panics as MISSING_BEHAVIOR with
a pointer to the workflow's stub-first section.
2026-05-07 05:42:16 +02:00
832306c817 fix(opencode): harden workflow against multi-task spec dumps
A workflow run on a Rust/Bevy task produced a single @make dispatch
covering six tasks (~2 hours of work), with the orchestrator drafting
the full replacement code, including a self-contradicting "actually
that's wrong, let me correct…" revision pass and a `nix develop
--command bash -c "cargo check"` invocation that @make's sandbox
denies. None of the failure modes were caught before dispatch.

Phase 5 gains three new subsections:
- Split Heuristic — explicit rules for when a task must be split
  (>2 concerns, >50 lines / 2 files, structural+runtime+wiring mix);
  prescribes the foundations / implementation / wiring split.
- Code Context Anti-patterns — the field is for seam-revealing
  snippets, not finished answers; max ~5-line snippets, no full
  replacement bodies.
- Finalized-Text Rule — task specs must be single-author finalized
  text, no "actually, that's wrong" revision passes, no two-version
  code blocks, no unresolved questions.

Phase 6 promotes the Rust unit-only NOT_TESTABLE case out of the
decision table into a dedicated routing subsection. The orchestrator
must pass test *specifications* (one-line behavior descriptions,
target functions, assertion types) to @make — never test code — and
run the suite once after @make to capture RED→GREEN evidence.

Phase 7 gains a mandatory Pre-Dispatch Validation table that rejects
specs containing `bash -c` / `sh -c` (any nesting), `nix develop -c
bash`, `cd <path> &&`, oversized Code Context blocks, contradictory
revisions, or duplicated test bodies. Repeated trips signal a Phase
5 split problem and route back to splitting.
2026-05-06 20:25:40 +02:00
d5d90d8b9f fix(opencode): reject Rust src/tests/ paths as a wrong task spec
A workflow run on a Bevy/Rust project produced the test-file path
`src/tests/test_<feature>.rs`, which @test correctly flagged as
contradictory: it isn't a valid Rust test location (would require
declaring `mod tests;` in production source, which @test cannot do)
yet the file-gate glob `**/tests/**/*.rs` accidentally matched it.

Phase 5 now gives language-aware Test File guidance: Python uses
colocated or top-level `tests/`, Rust uses crate-level `tests/<feature>.rs`,
and Rust unit-only tasks are routed to NOT_TESTABLE for @make to
handle inline. Phase 6's file gate gains an explicit anti-pattern
clause discarding any new file under `src/` even when the glob matches.

@test's own File Constraint mirrors the anti-pattern so the agent
rejects the bad path with BLOCKED before the orchestrator's gate
even runs — defense in depth on both sides of the dispatch boundary.
2026-05-06 18:31:14 +02:00
e2e35acdae refactor(opencode): assume opencode runs in the worktree, drop bare-repo plumbing
The workflow previously created a worktree itself (Phase 3) and worked
around opencode's lack of per-subagent CWD by capturing absolute paths
and threading them through every dispatch (the "Subagent Dispatch
Convention"). That ceremony exists only because the orchestrator's CWD
differed from where subagents were rooted.

Now the workflow assumes the user has already created the worktree and
launched opencode inside it. Subagents inherit that as their project
root, so all the absolute-path plumbing goes away. Phase 3 is removed,
phases renumber to 1-9, and the Subagent Dispatch Convention section
is dropped.

Phase 1 is a sanity check (non-bare worktree, TODO.md present, HEAD
not detached, current branch != base branch) that resolves the base
branch from an optional second argument or by trying main then master.
@pm now uses live filesystem mode against ./TODO.md throughout (the
git-ref read mode stays available for ad-hoc use). Phase 8's diff
uses git diff "$BASE_BRANCH"...HEAD without git -C wrapping.
2026-05-06 17:31:56 +02:00
8fcf7e5d34 feat(opencode): make @make and @test polyglot (Python, Rust, nix devshell)
Both agents previously hardcoded the Python/uv toolchain. They now
detect the language from marker files (pyproject.toml, Cargo.toml,
flake.nix) and run the appropriate test/lint/format/type-check commands
for Python, Rust, or both. When a flake.nix devshell is present, every
toolchain command is wrapped in `nix develop -c …`.

@make's permission allowlist gains `cargo *` and `nix develop -c *`,
plus matching denies for cargo add/remove/install/publish. The
Verification Tiers and Baseline Verification sections are rewritten as
per-language bullets, and output/TDD-evidence examples are now
language-neutral. Generalised the "no Kubernetes deployments"
constraint to cover any deploy/publish.

@test gains the same devshell + cargo allows (scoped to test, check,
clippy, fmt only — no build/run/install). Its file constraint adds
`tests/**/*.rs` for Rust integration tests, with an explicit note that
Rust unit tests stay with @make because they live inside production
source files. Failure-classification hints add Rust compiler-error
mappings, and the NOT_TESTABLE table gets a "Rust unit-only" row.
2026-05-06 17:09:34 +02:00
f750c76877 fix(opencode): keep workflow-summary.md local, never commit it
A per-branch artifact written by every run causes merge conflicts when
multiple workflow branches are merged together. The summary is now
documented as an intentionally untracked local file: not staged in the
main commit, not committed in its own commit, and not staged in the
failure-path WIP commit. Recommends the user add `.opencode/` to
`.gitignore`.
2026-05-06 16:51:19 +02:00
c879870ccf fix(opencode): remove temperature 2026-05-06 16:43:35 +02:00
28c7785816 fix(opencode): pass absolute worktree path to every subagent dispatch
Subagents do not inherit the orchestrator's `cd`, so dispatched prompts
that referred to files relative to the worktree were resolved against
the bare repo root and failed with "file not found" (observed when
@check tried to read src/main.rs after Phase 3).

Phase 3 now captures `WORKTREE_PATH="$(pwd)"` after entering the
worktree. A new "Subagent Dispatch Convention" section requires every
dispatch in phases 5, 7, 8, 9, and 10 to open with `Worktree: <path>`
and pass file references as absolute paths under `$WORKTREE_PATH/`.
Phase 9's diff command uses `git -C "$WORKTREE_PATH"` rather than
relying on shell CWD, and @pm updates receive the explicit absolute
path to `$WORKTREE_PATH/TODO.md`.
2026-05-06 15:56:45 +02:00
d22acf6906 refactor(opencode): let @pm read TODO.md via git show, drop tempfile
Gives @pm narrowly-scoped bash access (git show *, git rev-parse *) so
it can read TODO.md directly from any git ref. The workflow no longer
needs to mktemp + redirect the file before invoking the agent; Phase 2
just tells @pm the bare repo path and default branch and lets it run
git show "$DEFAULT_BRANCH:TODO.md" itself. Cleanup steps for the temp
snapshot are removed from Phase 10 and the failure handler.
2026-05-06 15:42:17 +02:00
37be2d9505 fix(opencode): remove agent models and temperature 2026-05-06 15:33:11 +02:00
2941faa822 refactor(opencode): make workflow forge-agnostic and read TODO.md from bare repo
Drops all GitHub-specific tooling (gh CLI, draft PR creation) so the
workflow stops at git commit and leaves push/PR/MR to the user.

TODO.md is now expected to be a tracked file on the default branch.
Phase 1 verifies the repo is bare via `git rev-parse --is-bare-repository`,
resolves the default branch from HEAD / init.defaultBranch, and snapshots
TODO.md via `git show "$DEFAULT_BRANCH:TODO.md"` to a tempfile that @pm
reads in Phase 2. Phase 10 updates the live TODO.md inside the worktree
and commits the change separately. The /review command drops its PR
mode for the same reason; @pm documents the read-only-snapshot vs.
live-worktree path distinction.
2026-05-06 15:28:08 +02:00
4ec1561af4 feat(opencode): add multi-agent workflow agents and commands
Adds @check, @simplify, @test, @make, @pm subagents and the /workflow
and /review slash commands from the autonomous multi-agent workflow
gist by ppries.

@pm is rewritten to manage issues in a local ./TODO.md file instead of
Linear (file-only access, documented schema, structured JSON output).

/workflow is adapted: TODO.md-based issue context, generic worktree
paths (no hardcoded ~/repos/veo/sunstone), generic branch examples,
and a Phase 1 guard that verifies origin is on GitHub before any
work begins.
2026-05-06 14:56:42 +02:00
02b3c73376 fix(halo): fix systemd description for llama 2026-05-06 14:03:28 +02:00
7ebd97629d feat(halo): use am17an/Qwen3.6-27B-MTP-GGUF:Q8_0 with MTP spec 2026-05-06 14:01:31 +02:00
9c465ac9fa fix(halo): remove -DGGML_HIP_ROCWMMA_FATTN=ON 2026-05-06 13:08:45 +02:00
a95417da8b feat(halo): use unsloth/Qwen3.6-27B-GGUF:UD-Q8_K_XL 2026-05-06 13:02:20 +02:00
c9c7f6916a fix(llama-cpp-rocm): wire rocwmma include path for hipcc
rocwmma is header-only and ships no CMake config file, so
find_package(rocwmma) is not available. hipcc/clang also bypass the
nixpkgs cc-wrapper that would normally pick up headers from
buildInputs, so the rocwmma path was unreachable and the build failed
with:

  ggml-cuda/vendors/hip.h: 'rocwmma/rocwmma-version.hpp' file not found

Inject -I<rocwmma>/include via CMAKE_HIP_FLAGS (HIP TUs) and
CMAKE_CXX_FLAGS (C++ TUs that include hip.h transitively).
2026-05-06 09:22:05 +02:00
f62e8ac470 perf(llama-cpp-rocm): tune for Strix Halo (gfx1151)
- Restrict rocmGpuTargets to gfx1151 (Radeon 8060S, RDNA 3.5) — smaller
  closure, faster compile, no wasted device kernels.
- Enable GGML_HIP_ROCWMMA_FATTN: rocWMMA-backed flash attention is a
  major win on RDNA3+ for the GPU-offloaded attention path.
- Enable GGML_HIP_GRAPHS to lower per-token launch overhead.
- Add rocwmma to buildInputs to satisfy the WMMA path.

llama-server on halo runs with -ngl 99 --flash-attn on, so these flags
target the hot path. CPU-side AVX-512 was skipped intentionally — Zen 5
has it, but with full GPU offload the CPU paths barely run.
2026-05-06 09:13:54 +02:00
623a71f95f fix(overlays): correct llama-cpp-rocm src hash to include postFetch COMMIT
The previous hash was the bare tarball hash; postFetch writes a COMMIT
file into the source, so the final fixed-output hash differs. My local
machine masked the bug by reusing a cached pre-postFetch store path
with the same FOD path. Verified by deleting the cached path and
re-fetching.
2026-05-06 09:07:53 +02:00
55b74f0caf feat(overlays): pin llama-cpp-rocm to am17an/mtp-clean fork
Override the unstable llama-cpp-rocm src to track the am17an/llama.cpp
mtp-clean branch (rev 267f8af). Replaces upstream's leaveDotGit-based
COMMIT extraction with a direct postFetch write so the source hash is
deterministic without a git clone. The fork's webui package-lock differs
from upstream, so npmDepsHash is repinned.
2026-05-06 08:43:46 +02:00
927e575828 fix(opencode): require -- before prompt in ask-claude skill
Variadic flags like --allowedTools and --add-dir were silently swallowing
the trailing prompt, causing `claude -p` to fail with "Input must be
provided through stdin or as a prompt argument". Mandate a uniform
`claude -p [flags] -- "<prompt>"` shape and document the gotcha.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-05 14:43:18 +02:00
393ff652c7 fix: add ssh key 2026-05-05 14:20:00 +02:00
Harald Hoyer
471b5a4f11 feat: map ./config/claude to ~/.claude 2026-05-05 14:15:50 +02:00
Harald Hoyer
289920b726 feat: add opencode commands 2026-05-05 14:14:25 +02:00
Harald Hoyer
b4f1514df1 feat: opencode skills 2026-05-05 14:13:16 +02:00
Harald Hoyer
77b7cd6259 feat: add more claude skills 2026-05-05 14:09:42 +02:00
2a389a49b2 fix(claude-code): track empty skills dir so flake source resolves
Git doesn't track empty directories, so config/claude/skills was missing
from the Nix store source path, breaking home.file.".claude/skills"
evaluation. Add a .gitkeep to keep the directory present until real
skills are added.
2026-05-05 14:08:23 +02:00
ba396eed12 feat(claude-code): manage commands and skills via home-manager
Add a home-manager module that symlinks config/claude/commands and
config/claude/skills into ~/.claude, mirroring the opencode module.
Seed the commands directory with a /commit slash command.
2026-05-05 14:03:44 +02:00
5d0e1fcdd6 docs(opencode): steer ask-claude skill toward repo access for reviews
Add a "Code review pattern" section that tells the opencode agent to give
claude read-only access to the repo (Read/Grep/Glob plus a narrow git
allowlist) instead of gathering a full `git diff` and piping it in. The
piped-diff form loses surrounding-file context, bloats the prompt, and
falls over on large branches. Also adds a matching entry to "Don'ts" and
caveats the existing pipe-stdin example.

Motivated by an opencode run that collected the entire branch diff as
stdin instead of pointing claude at the working tree.
2026-05-05 13:56:40 +02:00
425ee187cf chore(opencode): re-order models 2026-05-05 13:43:27 +02:00
3a1cb7487a refactor(opencode): extract serve service into shared NixOS module
New `metacfg.services.opencode` module under modules/nixos/services/opencode/
with options for port, user, homeDir, sopsFile, and extraPackages. User and
homeDir default off `metacfg.user`. Host configs for amd and sgx reduce to
enabling the module and pointing at their respective sops file.

Service PATH gains jq, yq-go, python3, gh, gnutar, gzip, unzip, wget,
diffutils, patch, file, tree, bun, uv, ast-grep, claude-code, and tmux for
agent ergonomics.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-05 13:43:27 +02:00
dbbb150bcc chore: refactor opencode service 2026-05-05 13:20:52 +02:00
da88a9b2d6 fix(halo): drop speculative HSA_OVERRIDE_GFX_VERSION from llama-server
Was set defensively without knowing the actual GPU arch; if ROCm
supports the card natively, the override is at best a no-op and at
worst masks the real arch. Add it back with the right value if the
service actually fails to detect the GPU.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-05 11:42:17 +02:00
b11e5c8356 feat(halo): add llama-server systemd unit for Qwen3.6-35B-A3B
Runs llama.cpp's ROCm build under DynamicUser, with the HF model cache
in StateDirectory (survives systemctl clean) and KV slot saves in
CacheDirectory. Listens on :8000.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-05 11:42:17 +02:00
Harald Hoyer
603e435db8 chore: fix opencode model config 2026-05-05 10:34:07 +02:00
624a72737c fix(opencode): narrow LD_LIBRARY_PATH to libstdc++ only
The full nix-ld library list shadowed nix's own curl, breaking
libnixstore.so with "CURL_OPENSSL_4 not found". The prebuilt node
watcher binding only needs libstdc++/libgcc_s, so use stdenv.cc.cc.lib
and let nix-built tools resolve their own deps via RUNPATH.
2026-05-04 08:58:37 +02:00
75d8b5354d chore: flake update 2026-05-04 08:44:12 +02:00
9f937cb789 chore(opencode): add disabled_providers config 2026-05-03 16:40:07 +02:00
0d5fb73022 fix(amd): opencode 2026-05-03 16:31:02 +02:00
8b205ea9f1 chore(opencode): switch to Qwen3-Coder-Next model 2026-05-03 16:29:56 +02:00
5693009488 fix(opencode): set LD_LIBRARY_PATH for prebuilt node bindings
The file watcher binding (and other node-precompiled .node modules
loaded via dlopen) failed with "libstdc++.so.6: cannot open shared
object file" because systemd services don't inherit the user shell's
LD path. Reuse the nix-ld library list so the service sees the same
common libraries unwrapped binaries get globally.
2026-05-03 16:29:24 +02:00
441df05d86 fix(opencode): add git and dev tools to service PATH
The opencode-serve unit ran with systemd's minimal default PATH, so
shell commands invoked by the agent (git, make, nix, node, rg, etc.)
were not found. Set systemd.services.opencode-serve.path on both sgx
and amd to a common dev toolset.
2026-05-03 16:09:31 +02:00
0e723e2da8 feat(amd): add opencode web server at opencode.amd.hoyer.world
Mirror of the sgx opencode setup: systemd service on port 4196 fronted
by nginx with a per-host ACME cert (DNS-01 via internetbs). Adds amd
key + path rule to .sops.yaml so secrets under .secrets/amd/ encrypt
for the host.
2026-05-03 15:55:15 +02:00
01f42c0851 feat(sops): trigger service restarts on secret rotation
Wire up restartUnits on secrets whose consumers cache them in memory
(daemons read at startup), so sops-nix restarts the affected unit on
activation when the decrypted content changes:

- firefly: app_key → phpfpm-firefly-iii;
  auto_import_secret + access_token → phpfpm-firefly-iii-data-importer
- searx: secret_key → uwsgi
- opencode: web password → opencode-serve
- mail: sasl_passwd → postfix
- forgejo: gitea_dbpass → forgejo; runner-token → gitea-runner-default

Secrets read on demand by oneshots/timers (firefly sparda_pin, ntfy
token, restic backup creds, acme dns creds, wg conf) are left as-is.
2026-05-03 15:23:40 +02:00
59480cdc79 chore: opencode pw 2026-05-03 15:14:54 +02:00
3453f412fc chore: opencode pw 2026-05-03 15:11:02 +02:00
0989b8ae46 feat(sgx): add opencode web server 2026-05-03 14:57:49 +02:00
f74928ce5f chore: nix fmt 2026-05-03 14:57:49 +02:00