Engineer a change in the Go modules (runner/ or mcp/) the house way — read the project AGENTS.md first, match the Go house style (slog, fmt.Errorf %w, stdlib table-driven tests, no new deps), honor the runner's security posture, and run the gate. Use for any code change in runner/ or mcp/ (the Go analog of the portal Elixir skills).
Installs into .claude/skills of the current project.
Are you the author of Go Engineer?
Add the live security badge to your README. It updates with every re-scan.
[](https://www.skillsdirectory.com/skills/andrewdryga-go-engineer)
---
name: go-engineer
description: Engineer a change in the Go modules (runner/ or mcp/) the house way — read the project AGENTS.md first, match the Go house style (slog, fmt.Errorf %w, stdlib table-driven tests, no new deps), honor the runner's security posture, and run the gate. Use for any code change in runner/ or mcp/ (the Go analog of the portal Elixir skills).
effort: medium
argument-hint: "<what to change in runner/ or mcp/>"
allowed-tools: Read, Grep, Glob, Bash, Write, Edit
---
# Go engineering (runner / mcp)
The Go analog of the portal skills. The rules live in the project's `AGENTS.md` —
this skill is the *order of operations*, not a copy of them.
## 1. Read the project AGENTS.md first
`runner/AGENTS.md` or `mcp/AGENTS.md`, in full. They carry the gate, the package
layout, the security posture, and the Go house style. Don't work from memory —
the conventions are specific (e.g. the runner never accepts cloud/LLM-controlled
shell code; open-ended values enter fixed shell programs only through env or
whole positional argv elements).
## 2. Wear the hats (the root manual's engineering contracts)
- **Security** especially for `runner/` — it executes commands on hosts. Any
change to validation / admission / redaction / exec **adds or extends** a
`*_security_test.go`. Ask: what's the abuse case?
- PM / UX / Maintainer for the rest — smallest correct change, reads clearly later.
## 3. Match the house style
- Errors are values: `fmt.Errorf("…: %w", err)`; `error` is the last return.
- `log/slog` only (runner); stderr `fatalln` is fine for the tiny `mcp` bridge.
- Tests: stdlib + table-driven (`t.Run`, `t.Helper`, `t.TempDir`) — no testify.
- Small single-purpose packages; pure types in `pkg/`, logic in `internal/`.
- A new dependency is new attack surface — justify it in one sentence or use stdlib.
## 4. Run the gate (Definition of Done)
From the repository root:
```
./run gate runner
./run gate mcp
```
Run only the gate for the module you touched. Use
`./run test <runner|mcp> [go-test-args...]` for focused feedback.
Linux-only runner behavior (Pdeathsig, `/var/log` symlinks): from the repository
root run `coop run -- go -C runner test -race -count=1 ./...`.
Show the output — never "should work". Don't pipe `go test`/`gofmt` through
`head`/`tail` (the pipe's exit code masks the tool's).
## 5. Close the loop
One focused commit (ending with its `Coop-Task: <id>` trailer) → append the
*what + why* to the task's `log.md` and overwrite its `state.md` with the outcome
and validation → `coop tasks done <id>`. Blocked? `coop tasks block <id>` and
fill its `decision.md`. The pre-commit hook gofmt-checks your staged `.go`.