13 Commits
Author SHA1 Message Date
mathiasandClaude Opus 5 2b3851a09e fix(template): children were red because ./... cannot see the entrypoint
CD / Lint / Test / Vet (push) Successful in 9s
CD / Build & Import (push) Skipped
CD / Deploy via GitOps (push) Skipped
Closes #1. Closes #2.

A repo generated from this template failed `task check` on errcheck from its
first commit, while the template's own `task check` was green. The reason is
not in the code:

    Go ignores directories whose names begin with "_" or "." when expanding
    package patterns like ./...

The entrypoint lives in cmd/__PROJECT_NAME__. So `go build ./...`,
`go vet ./...`, `go test ./...` and `golangci-lint run ./...` ALL silently
skip the one package every generated repo is built around:

    $ go list ./...
    __MODULE_PATH__/internal/agent
    __MODULE_PATH__/pkg/litellm        <- no cmd package

After substitution the directory has a real name, becomes visible, and the
defect appears. Template green, children red, by construction -- and invisible
to anyone reading either repo's CI.

Fixes the one live defect: `defer shutdown(ctx)` dropped an error, and
SetupTelemetry returns func(context.Context) error.

Two of the three defects these issues describe were already fixed and neither
issue knew: go.sum has been committed for some time, and resp.Body.Close is
already wrapped. Verified before touching anything rather than trusted from
the issue text.

Adds scripts/tests/generated-child_test.sh, wired into `task check`: it
substitutes the tracked tree into a throwaway child and gates go list / build
/ vet / golangci-lint on the RESULT. Without it the next entrypoint defect
rots exactly the same way.

Not done by adding ./cmd/__PROJECT_NAME__ to the lint command, which does work
-- naming a path directly bypasses the pattern exclusion -- because it reports
a gofumpt violation on the import block that does not exist in any child. The
formatter's import grouping depends on the module path and the template's is a
placeholder, so that route turns the gate red over an artifact of being a
template.

The harness reads tracked files from the working tree rather than
`git archive HEAD`: it runs inside `task check`, so it must gate what is about
to be committed. Archiving HEAD reported a stale pass against an unstaged fix
on first use here.

Proven to fail when it should: red on the unfixed entrypoint, and red again on
the stale-HEAD read, before going green.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-17 18:00:00 +02:00
mathias 607c5fec3a chore(lint): adopt the canonical .golangci.yml from infra/ci-templates
CD / Lint / Test / Vet (push) Successful in 4s
CD / Build & Import (push) Skipped
CD / Deploy via GitOps (push) Skipped
Estate had 26 Go repos, 3 with a lint config, all three different; the other
23 ran golangci-lint v2 defaults, which enable NO formatter -- the hole that
let gofmt drift rot undetected until it was found by hand (dma-cli#12).

Canonical lives at infra ci-templates/golangci.yml and is distributed by the
infra#309 pattern: byte-identical copies, checksum drift gate in infra. Do
not edit this file here -- edit the canonical and run `task ci:sync`.

Verified locally before pushing, not pushed-and-hoped: golangci-lint v2.11.4
run against a Go 1.26.1 toolchain (matching CI) reports 0 issues in this
repo with this config.
2026-09-05 12:51:06 +02:00
mathiasandClaude Opus 5 d8d29664a3 ci(deploy): refuse to patch a manifest with an empty IMAGE_TAG (infra#311)
CD / Lint / Test / Vet (push) Successful in 7s
CD / Build & Import (push) Skipped
CD / Deploy via GitOps (push) Skipped
On 2026-08-25 a deploy job ran with an empty IMAGE_TAG, wrote
`image: localhost:5000/gitea-mcp:` into the infra repo and pushed it.
That is invalid YAML, so Flux failed the ENTIRE apps Kustomization --
every app stopped reconciling for about an hour, including three
unrelated deploys queued behind it.

This job's existing check could not catch it. It greps for
`image: <repo>:${IMAGE_TAG}` after the sed, and with IMAGE_TAG empty that
pattern matches the corrupted line itself, so the verification passes
because of the bug rather than despite it.

Asserting the input up front is the fix: an empty tag now fails the job
before anything is written, let alone committed.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011PL5XcG68SvQqz3vGVbWbf
2026-08-25 17:25:24 +02:00
mathiasandClaude Opus 5 020edc5b3a ci: re-sync build-image.sh — adds TARGET and BUILD_SECRETS (infra#309)
CD / Lint / Test / Vet (push) Successful in 7s
CD / Build & Import (push) Skipped
CD / Deploy via GitOps (push) Skipped
Canonical gained two inputs so the repos still to migrate can adopt
without forking the script again: TARGET for multi-stage builds (cad,
agentsquad) and BUILD_SECRETS for buildkit secret mounts (agentsquad).

BUILD_SECRETS takes the SPEC only (`id=NAME,src=PATH`) -- the caller
writes the secret to PATH itself, so no secret value ever reaches this
script's argv or the CI log.

Unused here; this repo's copy just stays byte-identical, which is the
whole point. Written by `task ci:sync`, not by hand.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011PL5XcG68SvQqz3vGVbWbf
2026-08-25 11:27:06 +02:00
mathias add5428e2f ci(cd): call the shared build-image script instead of inlining it (infra#309)
CD / Lint / Test / Vet (push) Successful in 5s
CD / Build & Import (push) Skipped
CD / Deploy via GitOps (push) Skipped
A template is the highest-leverage copy of anything. This one carried its
own inline build step, so every generated repo was born with a private
fork of the build logic -- which is how rootless buildah reached a dozen
repos before infra#241, and why the fix then had to be rediscovered here
weeks after the app repos were done.

The step now calls .gitea/build-image.sh, a byte-identical copy of
mathias/infra's ci-templates/build-image.sh. Generated repos inherit the
script and the call; adding the new repo to infra's adopters.txt puts it
under the drift gate.

Invoked as `bash .gitea/build-image.sh` rather than relying on the exec
bit: files written through the Gitea API land 0644, and a template whose
CI depends on a file mode is a trap for every repo generated from it.
2026-08-25 08:52:26 +00:00
mathias cfd55aeedb ci: carry the shared build-image script (infra#309)
CD / Lint / Test / Vet (push) Successful in 6s
CD / Build & Import (push) Skipped
CD / Deploy via GitOps (push) Skipped
Byte-identical copy of mathias/infra's ci-templates/build-image.sh. A
template that carries its own copy of the build LOGIC manufactures a new
copy of every bug in it -- which is exactly how rootless buildah reached
a dozen repos (infra#241). Now it manufactures a copy of one file that a
drift gate keeps current instead.
2026-08-25 08:51:53 +00:00
mathias c704fed563 ci: build with buildctl instead of buildah (infra#241)
CD / Lint / Test / Vet (push) Successful in 7s
CD / Build & Import (push) Skipped
CD / Deploy via GitOps (push) Skipped
Rootless buildah in gitea-runner's hardened securityContext (capabilities:
drop [ALL], allowPrivilegeEscalation: false) cannot remap the UID/GID range
newuidmap/newgidmap need on a fresh base-image pull, and the pod has no OCI
runtime at all. buildctl talks to the host's buildkitd over a socket, so the
privileged layer extraction happens on the host and the pod's securityContext
stops being in the picture. Same pattern as mathias/infra's segment-embedder.yml
and postgres18.yml.

A template is the highest-leverage place to fix this. Every repo generated from
here inherits its CI, so a buildah-based template does not just carry the bug —
it manufactures new instances of it. A fleet inventory for infra#241 found nine
repos still invoking buildah, and two of them are the templates.

Note the failure is latent, not immediate: warm base-image layers mask it, so a
generated repo builds fine until the first genuinely cold pull. That is exactly
the situation a NEW repo is in.

Verified by running the exact command against this repo's real build context:

    buildctl --addr unix:///run/buildkit/buildkitd.sock build \
      --frontend dockerfile.v0 --local context=. --local dockerfile=. \
      --output type=oci,dest=$TAR
    -> exporting manifest sha256:5a841529... DONE, 6.8MB OCI archive

That check matters here because this repo's own CI cannot validate the change:
the build job is deliberately skipped on the raw template (2ba2698), since
__PROJECT_NAME__ is not a legal image name. The next generated repo is the first
place it runs for real.

skopeo copy replaces `buildah push` — buildctl has no registry-push equivalent —
and runs twice to preserve the :sha and :latest tags the previous version pushed.
2026-08-21 18:29:55 +02:00
mathias 2ba2698ea6 fix(ci): skip build/deploy on the raw template repo itself (template-go-agent#3)
CD / Lint / Test / Vet (push) Successful in 6s
CD / Build & Import (push) Has been skipped
CD / Deploy via GitOps (push) Has been skipped
env.IMAGE: __PROJECT_NAME__ is only substituted with a real, lowercase
project name when a repo is *generated* from this template. On the
template repo itself it's still the literal placeholder, which
buildah/Docker reject outright ("repository name must be lowercase") --
build (and therefore deploy) can never succeed here no matter what else
changes. Gate both on github.repository != this template's own path so
the template's CI reads green on what it actually validates: the check
job (lint/vet/test), the thing every generated repo inherits.
2026-07-24 15:22:04 +02:00
mathias 06d4ac6076 fix(ci): go mod tidy + check resp.Body.Close error (template-go-agent#3)
CD / Lint / Test / Vet (push) Successful in 24s
CD / Build & Import (push) Failing after 1s
CD / Deploy via GitOps (push) Has been skipped
Template shipped with no go.sum and an unchecked resp.Body.Close(),
both failing `task check` (golangci-lint errcheck) on every push since
bootstrap -- every repo generated from this template inherited the same
red CI. go.sum generated via `go mod tidy`; Close() error explicitly
discarded (best-effort cleanup, nothing actionable to do with it).
2026-07-24 15:19:17 +02:00
mathiasandClaude Opus 4.8 c6f8ea477b refactor(template): match single-harness (hyperguild) architecture (infra#178)
CD / Lint / Test / Vet (push) Failing after 3s
CD / Build & Import (push) Has been skipped
CD / Deploy via GitOps (push) Has been skipped
The template carried the old multi-tool/agentsquad-era CAD-executor scaffold.
Refresh it to the consolidated single-harness reality (hyperguild#75/#76):
Claude Code + hyperguild, session-based, brain + gitea MCP. No dispatch
automation added (out of scope — dispatch stays manual until real friction
warrants it).

Removed (multi-tool + dead generator + deployed-agent-era):
- .aider.conf.yml, .aider.conventions.md, .cursorrules
- .context/ (mcp.json, PROJECT.md, system-prompt.txt)
- agent-policy.yaml (k8s NetworkPolicy scaffold)
- scripts/context-sync.sh (generated the above from .context/PROJECT.md — now
  input-less) + its context:sync* Taskfile tasks

Added / updated:
- .mcp.json (root, hyperguild-shaped: brain + gitea, Bearer env tokens)
- CLAUDE.md / AGENTS.md / README.md → single-harness workflow (issue →
  hyperguild session → PR → report-back comment → brain capture)
- AGENT_BOUNDARIES.md kept (harness-agnostic egress/scope guidance); repointed
  its two references to the removed agent-policy.yaml

Left alone: cd.yml, Dockerfile, Taskfile (build/test), go.mod, cmd/, internal/,
pkg/, .claude/. No dangling refs to removed files (verified). Refs infra#178.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-01 22:20:37 +02:00
mathias 2c6d1e1149 fix(ci): quote "on" key so Gitea parses workflow triggers
CD / Lint / Test / Vet (push) Failing after 2s
CD / Build & Import (push) Has been skipped
CD / Deploy via GitOps (push) Has been skipped
Bare on: parses as YAML boolean true (Norway problem); Gitea then ignores the triggers and silently skips jobs. Quoting forces the string key.
2026-06-03 08:38:47 +02:00
mathiasandClaude Opus 4.7 b9c64c2694 feat: add agent boundaries, network policy, agent stub, dockerfile, CI
CD / Lint / Test / Vet (push) Failing after 4s
CD / Build & Import (push) Has been skipped
CD / Deploy via GitOps (push) Has been skipped
- AGENT_BOUNDARIES.md: egress allow-list, FS scope, approved/forbidden ops
- agent-policy.yaml: k8s NetworkPolicy scoping egress to LiteLLM/brain-mcp/
  gitea-mcp/OTLP + default-deny baseline
- internal/agent/agent.go: thin ADK runner wrapper (Config + Run)
- Dockerfile: distroless multi-stage build, entrypoint cmd/__PROJECT_NAME__
- .gitea/workflows/cd.yml: check → buildah build/push → GitOps deploy

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-28 20:54:04 +02:00
mathiasandClaude Sonnet 4.6 7dfe8a792e feat: initial scaffold with context adapters and litellm pkg
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-19 23:02:07 +02:00