Commit graph

854 commits

Author SHA1 Message Date
Harald Hoyer
5b44e037a1 feat(halo): add song <URL> command to convert via song.link
Resolves the URL through the Odesli public API (api.song.link) and
replies with the canonical song.link page plus per-platform deep links
(Spotify, Apple Music, YouTube/YT Music, Tidal, Deezer, Amazon Music,
SoundCloud). Country is pinned to DE.
2026-05-20 09:42:11 +02:00
ac70c57c15 chore(halo): preload both llama models and tune preset
Preload Qwen3.6-27B and Qwen3.6-35B-A3B at startup (load-on-startup)
so both are warm immediately under --models-max 2, set parallel = 1
as the [*] fallback for any other model, and adjust per-model context
size and draft depth.
2026-05-20 07:14:26 +02:00
31e491e314 Revert "fix(halo): 27 only"
This reverts commit 72e7bf613f.
2026-05-20 07:05:27 +02:00
72e7bf613f fix(halo): 27 only 2026-05-20 02:14:08 +02:00
807a3d0d8e fix(halo): context 2026-05-20 01:21:10 +02:00
0edf975c30 feat(halo): serve multiple llama models via models.ini preset
Replace the per-model llama-server units with a single service that
uses llama-server's --models-preset (models.ini) and --models-max 2,
so the 35B-A3B and 27B models are loaded on demand from one config.

Drop the now-redundant 27B / 27B-MTP / coder-next variant files and
the unused CacheDirectory + slot-save-path KV-slot handling.
2026-05-20 00:23:50 +02:00
ae068cfd84 feat(mx): increase halo bot timeout 2026-05-19 23:52:46 +02:00
b4063fda66 feat(halo): MTP --parallel 2 2026-05-19 23:48:53 +02:00
Harald Hoyer
f07af7f5da feat(skills): add adversarial-review
A skeptical PR review skill that defaults to REJECT. Encodes the
staff-engineer adversarial stance: lead with problems, assume bugs
exist, require severity+location+fix+test per finding, mandate an
execution trace, and end with an explicit verdict.

Includes base-branch detection (gh pr view → upstream → heuristic →
ask) so the review never silently diffs against the wrong base.
2026-05-19 15:03:28 +02:00
Harald Hoyer
5b92ed1850 feat(rialo): add pi 2026-05-19 14:27:50 +02:00
3631e2fe81 chore: flake.lock update 2026-05-19 06:40:44 +02:00
bbca21240f feat(halo): new llama-cpp-rocm 2026-05-19 06:40:13 +02:00
8bd096ff8d feat(halo): inc. mtp to 6 2026-05-19 06:40:13 +02:00
46cdf2f6f6 Revert "feat(halo): new MTP version"
This reverts commit 53c11a120c.
2026-05-19 06:40:13 +02:00
Harald Hoyer
b185a6159f feat(darwin): enable launchd ssh-agent with FIDO/SK support
Apple's built-in ssh-agent has no sk-api/libfido2 support and refuses
signing operations for ed25519-sk / ecdsa-sk hardware keys. Enable the
existing metacfg.security.ssh module (which runs pkgs.openssh's
ssh-agent under launchd) via the common darwin suite, and export
SSH_AUTH_SOCK from environment.shellInit so bash, zsh, and fish (via
/etc/fish/foreign-env/shellInit) all point at the nix-managed socket.
2026-05-18 12:18:22 +02:00
0990389464 feat(m4): install defuddle-cli 2026-05-16 14:13:31 +02:00
a29301179b feat(opencode): install kepano/obsidian-skills into ~/.agents/skills
Add obsidian-skills as a flake input (flake = false) and map each
skill subdirectory into ~/.agents/skills/<skill>, alongside the
existing local skills. Updates flow through `nix flake update
obsidian-skills`.
2026-05-16 14:13:31 +02:00
b0fc627d0a feat: add config/claude/statusline-command.sh 2026-05-16 13:41:09 +02:00
492362fa31 feat(amd): enable Wake-on-LAN on enp7s0 2026-05-16 13:40:25 +02:00
4da2eed356 chore(homes): remove broken x86_64-linux home configs
- harald@sgx-nixos: orphan, no matching NixOS system and no
  home.stateVersion set, so it failed standalone evaluation
- harald@sgx-azure: referenced metacfg.tools.direnv.enable but no
  modules/home/tools/direnv exists, causing eval failure
2026-05-16 11:26:31 +02:00
a2b7dc510b fix(pi): PI_OFFLINE 1 2026-05-16 08:51:46 +02:00
4d32148059 chore: use ~/.agent/skills 2026-05-15 21:26:56 +02:00
c65c0d8756 chore(opencode): remove domain from config 2026-05-15 20:41:44 +02:00
53c11a120c feat(halo): new MTP version 2026-05-15 19:32:51 +02:00
Harald Hoyer
b5ae777a4a feat(home/js): deploy ~/.npmrc and ~/.bunfig.toml everywhere
New metacfg.cli-apps.js module (enabled by default) pins minimum
release ages for npm and bun across all home configurations, so the
mitigation against newly published malicious packages applies
uniformly rather than living as untracked dotfiles on one machine.
2026-05-15 08:41:56 +02:00
38d2d4f4ae fix(halo): q6_k with mtp 2 2026-05-15 07:47:43 +02:00
baaab26eb7 chore: flake.lock 2026-05-14 08:04:19 +02:00
1e3b2fc9a7 feat(halo): unsloth MTP 2026-05-13 19:42:54 +02:00
42c52bd87f refactor(mx): drive opencode bot via direct chat-completions API
The bot no longer shells out to `opencode run`. Instead it POSTs to the
OpenAI-compatible /chat/completions endpoint exposed by llama-server on
halo.hoyer.tail:8000 directly. This removes the Bun/sqlite cold-start
overhead per request, drops the pkgs.opencode runtime dependency, and
eliminates the ExecStartPre dance that materialized config.json into the
service's $HOME.

Conversation history is now stored as a proper OpenAI `messages` list
with system/user/assistant roles, instead of the XML blob that was
inlined into a single `opencode run` argument. The interactive opencode
setup (config/opencode/config.json) is unchanged — only the bot stops
depending on it.

The module gains a `modelBaseUrl` option; `model` is now the bare model
name (`halo-8000`) without the provider/ prefix that the opencode CLI
required.
2026-05-13 16:38:58 +02:00
aa3bc3c457 feat(pi): package @earendil-works/pi-coding-agent as pi
Vendors the npm tarball + lockfile and wraps the `pi` binary with `fd` and
`ripgrep` on PATH. Also installs it on the m4 darwin host.

`buildNpmPackage` is pulled from `inputs.unstable` because nixos-25.11's
`prefetch-npm-deps-0.1.0` panics on cacache index entries that contain
either multiple lines or JSON values with embedded spaces (npm's
`accept: application/...; q=1.0, ...` headers). For this lockfile,
`@esbuild/netbsd-arm64` and `@rollup/rollup-linux-x64-musl` trigger
both conditions and `--map-cache` fails with `EOF while parsing a
string at line 1 column 369`. Fixed upstream in nixos-unstable, which
now uses `lines()` + `split_once('\t')`.
2026-05-13 16:34:38 +02:00
9e692f45ba chore: bot pw 2026-05-13 15:31:26 +02:00
d8e8293c0e feat(mx): add Nextcloud Talk opencode bot pointing at halo.hoyer.tail:8000
Mirrors the existing nextcloud-claude-bot setup but invokes `opencode run`
against the local `halo-8000` provider/model. The bot listens on
127.0.0.1:8086, is exposed via the `/_opencode-bot/` location on
nc.hoyer.xyz, and uses `@Halo` as its mention trigger in group chats.

The opencode config (config/opencode/config.json) is installed into the
service's $HOME/.config/opencode/ on each start, so the bot picks up the
same provider definition the user uses interactively. The model map keys
are renamed to `halo-8000` / `halo-8001` so the canonical
`provider/model` reference works without an alias indirection.
2026-05-13 15:08:18 +02:00
dadfb07914 fix(halo): set --alias halo-8000 2026-05-13 14:52:49 +02:00
83b2ed3b57 fix(opencode): full halo URL 2026-05-13 14:42:25 +02:00
fb32301831 chore(opencode): fix URLS 2026-05-13 11:40:04 +02:00
f9a2e0d301 chore(x1,amd): disable cratedocs-mcp service
Keep it enabled only on sgx.
2026-05-13 11:35:59 +02:00
4ce7bcf354 fix(mx): make tailscale exit-node advertisement actually apply
tailscale set is strict about boolean flags and silently ignores
--advertise-exit-node without =true. Result: the tailscaled-set unit
ran cleanly but AdvertiseRoutes stayed null. Spell the value out so the
flag takes effect.
2026-05-13 09:28:20 +02:00
b9cfdc99a7 feat(base): blacklist unused network kernel modules
Disable rxrpc, kafs, af_key, esp4, esp6 across all systems that enable
metacfg.base. None of them are used on these hosts, and they have a
history of CVEs — blacklisting reduces kernel attack surface.
2026-05-13 09:16:21 +02:00
67b7c3a9fd feat(headscale): add ACL policy, isolate mx, make mx an exit node
Introduces a headscale ACL policy (file-mode) plus matching client config:

- New systems/x86_64-linux/attic/headscale-policy.hujson:
  * tag:llm restricts a node to talking only to halo:8000
  * all other harald@ nodes have full mesh access to each other
  * harald@ nodes can route internet traffic via approved exit nodes
  * autoApprovers.exitNode = [tag:llm] auto-approves the exit route
    advertised by any tag:llm node (currently mx)

- attic headscale.nix: wire policy.mode = "file" / policy.path to
  the .hujson above.

- mx default.nix: enable useRoutingFeatures = "server" (needed for IP
  forwarding) and add extraSetFlags = ["--advertise-exit-node"] so the
  flag is reapplied on every activation, not just initial login.

Operational steps after deploy:
  headscale nodes tag -i 10 -t tag:llm
2026-05-13 09:06:40 +02:00
87bdaf15da fix(attic): keep headscale domain as headscale.hoyer.xyz
Avoid breaking existing clients and the registered OIDC redirect URI by
keeping the original domain. Only the host backing it changes (mx -> attic);
DNS just needs to be repointed.
2026-05-13 08:48:37 +02:00
12c25bcde8 refactor(attic): move headscale from mx to attic
Headscale is moving off the mx mailserver onto the attic cache host.
The new public URL is https://headscale.hoyer.world.

- Switch from useACMEHost = "hoyer.xyz" (mx wildcard DNS-01) to
  enableACME = true, since attic only has HTTP-01 configured.
- Move headscale port to 8081 to avoid clashing with atticd on 8080.
- Drop the 192.168.178.254 LAN nameserver from dns.nameservers.global,
  which isn't reachable from the Hetzner instance.

Operational steps still required on attic:
- Provision /var/lib/headscale/client_secret
- Migrate the headscale state DB from mx
- Point headscale.hoyer.world DNS at attic
- Update the Nextcloud OIDC client's redirect URI
2026-05-13 08:42:46 +02:00
1094facb1e refactor(opencode): use $1 substitution, drop BASE_BRANCH and arg parsing
The workflow command was asking the model to parse $ARGUMENTS into
positional tokens (issue ID, optional base branch). Opencode supports
$1, $2, $3, ... for direct positional substitution at template-load
time — the model never needs to see or parse a joined argument string.
Two simplifications:

1. Replace $ARGUMENTS-parsing with $1. Every reference to the issue ID
   in commands/workflow.md is now $1, which opencode substitutes
   literally before the prompt loads. Eliminates a class of parsing
   errors (whitespace edge cases, mis-splits, hallucinated extra args)
   and removes the orchestrator's need to "remember" an ISSUE_ID
   variable across phases.

2. Drop BASE_BRANCH entirely. It was used in three places:
   - Phase 1 "branch != base" check — actual concern is "don't run on
     a protected branch." Replace with refusal on main/master/develop/
     any matching protected name.
   - Phase 8 `git diff "$BASE_BRANCH"...HEAD` — anchor the diff to
     START_SHA captured at Phase 1 instead. With one-task-per-run
     (ADR-21), the run produces a small bounded diff from a known
     starting point; START_SHA is more accurate than diffing against
     a separate branch tip that may have moved.
   - Failure Handler recovery procedure — user-facing instructions;
     name "your usual integration branch" instead of $BASE_BRANCH.

The command signature collapses from `/workflow <ISSUE-ID> [base-branch]`
to just `/workflow <ISSUE-ID>` — single positional, zero parsing.

Routing matrix Phase 1 row updated for the protected-branch refusal;
ADR-14's recovery-procedure paragraph no longer names BASE_BRANCH.

Refs: config/opencode/workflow-design.md ADR-14, ADR-21
2026-05-13 07:20:41 +02:00
e440bf39fd feat(halo): llama-server-27B-MTP.nix 2026-05-12 16:16:15 +02:00
33690dcc98 feat(halo): new mtp llama.cpp 2026-05-12 16:14:13 +02:00
ca4ee90828 feat(halo): coder next 2026-05-11 12:22:34 +02:00
7b04b55ce8 feat(halo): cache-ram 0 2026-05-10 20:50:08 +02:00
04342222a2 fix(halo): 27b 2026-05-10 20:46:12 +02:00
689cdec28d feat(halo): activate qwen 27b 2026-05-10 20:44:38 +02:00
bef528e26a feat(halo): use qwen-35b-a3b 2026-05-10 20:44:38 +02:00
267c05b107 feat(opencode): give @make a concrete test-smell checklist
Real-world observation: @make struggles when @test sets up tests
incorrectly because the existing escalate: test_design trigger is
described abstractly ("test seems to demand wrong thing"). When @make
sees an unfamiliar smell, it tends to attempt implementation, fail,
attempt again, and only escalate after burning 2-3 cycles. The
protocol exists; the recognition criteria don't.

Restructure Entry Validation step 5 into a named "Test triage" step
with a concrete checklist that fires *before* any implementation
attempt. Four categories of smells:

- **Mocking smells:** mocks the SUT, >2 mocks, mock-call-as-primary
  assertion, internal-boundary mocking
- **Structural-only smells:** variant counts, type ascriptions,
  function-pointer coercion, struct-literal-with-field-reads,
  stub-first no-panics (mirrors @test.md's anti-patterns)
- **Wrong-target smells:** asserts on private state / log strings,
  demands contradicting spec, physically impossible demands
- **Setup smells:** fixtures bypassing production validation,
  wrong-module imports, references to nonexistent infrastructure

Iteration Limits step 5 now cross-references the same checklist
instead of restating abstract criteria, so both gates apply the same
recognition rules with a single source of truth.

A "NOT for" caveat prevents over-eager escalation: when the test is
fine but the implementation is just hard, that's not a smell, that's
the test doing its job.

The checklist is inlined (not pulled from @test.md at runtime) because
subagents have separate contexts. Periodic manual sync between
@make.md's checklist and @test.md's anti-patterns is acceptable —
they shouldn't drift much in practice.

Refs: config/opencode/agents/test.md (anti-patterns + structural-only
list it mirrors), config/opencode/workflow-design.md ADR-19 (unified
Implementation Incomplete diagnosis path)
2026-05-08 15:16:33 +02:00