How I Use AI
How I configure agent-skills: keeping things harness-agnostic, strict operational rules, MCP servers, and repeatable skill pipelines.
Most chat around using AI for engineering seems to land on two extremes: either people claiming agents will replace developers by next month, or complete cynicism because a model botched a regex. Neither feels particularly helpful to be honest.
I use coding agents every single day across multiple codebases. I don’t treat them like magical answers to everything, and I definitely don’t let them dump unvetted code into my repositories. For me, an agent is essentially a very fast, enthusiastic junior engineer who happens to be a bit careless if you leave them unsupervised. That means giving them strict boundaries, making TDD non-negotiable, and having zero patience for apologies or boilerplate slop.
All of this lives in my
agent-skills repo. Here is a
look at the mental model, the setup, and how work actually gets done.
๐ Don’t Marry Your Harness (Stay Agnostic)
The CLI agent ecosystem moves ridiculous fast. Every few months there’s another tool or harness turning up: Claude Code, Pi, Gemini CLI, OpenCode, Copilot CLI, and whatever else launched this morning. Tying your prompts, custom tools, and habits to one specific harness is a bad idea. The second you want to switch (or the project dies), you lose everything.
I say this from painful personal experience. I was once so invested in OpenCode that I forked it to fix a bunch of issues, adding prompt history search, subagent cost tracking, and skill autocomplete. I tried contributing those changes back upstream. But with hundreds of PRs sitting stale and an unresponsive maintainer, none of it got merged. It wasn’t for lack of trying, but I quickly realised OpenCode had too many architectural headaches under the hood and wasn’t going to work out long term.
So I moved over to the Pi harness instead. Naturally, I still wanted deeper
capabilities like subagent orchestration, better terminal telemetry, transcript
highlighting, and side conversations. So I built extensions for them:
pi-statusbar,
pi-subagents,
pi-btw, and
pi-transcript-enhancer.
There is an important distinction to make here, though. Right now, the industry doesn’t have a cross-harness standard for runtime extensions. If you want rich runtime features like subagents or custom terminal UI, you inevitably have to write against whatever plugin API your harness provides. If I switch harnesses down the road, that glue code is what I’d have to adapt.
What can be standardised, however, is the actual intelligence: the prompt logic, workflows, and operational conventions. The emerging “Skills” format gives us a portable way to do that. By keeping the core skills and conventions strictly harness-agnostic, the way I actually work isn’t locked into Pi, Claude Code, or anything else.
My agent-skills repo reflects this separation with a single source of truth:
.agents/ # Canonical skills + conventions
โโโ AGENTS.md # Shared operational conventions
โโโ skills/ # Canonical skills (1 dir per skill)
.claude/ # Claude Code adapter
โโโ CLAUDE.md # Pointer to ~/.agents/AGENTS.md
โโโ rules/ # Auto-generated path-scoped rules
โโโ skills -> ../.agents/skills # Symlink to canonical skills
.pi/agent/ # Pi harness configuration
โโโ settings.json # Defaults, models, and packages
โโโ themes/nord-contrast.json # Custom theme
mcp/google-workspace/ # Bundled Google Workspace MCP server
The core directory is .agents/skills/. Every skill is written using generic
instructions (“prompt the user”, “spawn a subagent”, “read the file”). Claude
Code gets access via a symlink (.claude/skills -> ../.agents/skills), while Pi
or Gemini CLI load them straight from ~/.agents/skills/.
When Claude Code supports handy features like path-scoped rules in
.claude/rules/, I generate them automatically from the canonical conventions
skills (conventions-go, conventions-python, and so on) via make rules.
# Install everything across all harnesses cleanly
make install
make install uses
scripts/op-inject.sh
to inject 1Password secrets for API keys and MCP configs at install time. If
1Password isn’t signed in, it quietly skips those injections instead of
blowing up.
๐ Ground Rules (Stop the Fluff)
Left to their own devices, agents default to people-pleasing nonsense. They
apologise constantly, hallucinate libraries, churn out paragraphs of
throat-clearing filler, and edit files nobody asked them to touch. My global
AGENTS.md sets the boundaries so we don’t have to have that argument every
session.
๐ฌ 1. Communication and Tone
- Cut the sycophancy: Drop the “I would be delighted to help with that!” nonsense. Lead with the direct answer.
- Keep it brief: Shortest complete response wins. Cap lists at around five items and group them by priority.
- Bound the steps: If a task takes multiple steps, number them upfront so I
know where we are. My
pi-transcript-enhancerextension parses progress labels (likeStep X/Y: <summary>) and renders them as high-contrast gold blocks in the TUI, keeping long sessions scannable at a glance without modifying the raw message sent to the model. - No robotic fluff: Drop literary flourishes and hedging throat-clearing. Keep the tone warm, plainspoken, and peer-to-peer.
- Load-bearing emoji only: Emoji are fine if they signal status faster than words (โ pass, โ fail, โ ๏ธ caution). Otherwise keep them out of running prose and code.
๐งช 2. Engineering Discipline & TDD
- Strict TDD: No production code without a failing test first. Stub first, prove failure on assertion (not compilation failure), write the minimum code to pass, and delete assertions that survive an inverted requirement.
- Simplicity over layers: I prefer solving problems by removing components rather than stacking abstractions or wrapper functions.
- Cite actual sources: Never guess an API signature or config header from
vague memory. Cite the file and line number
(
internal/parser/frontmatter.go:42), or explicitly flag it as an unverified assumption.
โ 3. Sceptical Code Edits
- Ask before editing: An inquiry is just an inquiry, not an open invite to start hacking on files. The agent has to propose the diff in chat and wait for approval before running edit tools.
- Summarise large diffs: Anything over 40 lines gets a one-line summary first, rather than dumping a massive wall of code into chat unprompted.
โ๏ธ The Skill Pipeline: How Work Actually Gets Done
A common mistake is asking an agent to “build feature X” in a single prompt. That almost always produces over-engineered junk (and a massive headache to debug). Instead, I break work down into a pipeline of smaller, specialised skills.
Product track: pdd (project โ discovery โ design) โโ
โโโ to-spec โ to-plan โ to-tasks โ next-slice
Engineering track: architect (research โ grill) โโโโโโโโ
๐ต๏ธ Phase 1: Interrogation (Poking Holes First)
Before touching code, the idea needs stress-testing.
clarify: Digs into what you actually want when a prompt is too vague. It asks targeted questions to remove ambiguity upfront.grilling(andgrill-me): Puts the idea through an adversarial interrogation. The agent relentlessly challenges your assumptions, edge cases, and architecture choices across the design tree.perspectives&decide: Evaluates alternatives through structured lenses (risks, benefits, costs) and produces a durable decision memo or ADR (Architecture Decision Record).consensus: Drives cross-model debate through gated discussion rounds, preserving healthy dissent when evaluating high-stakes architectural choices.arena: Runs parallel candidate attempts across multiple models for tricky pieces where a single shot risks locking in the wrong shape. It scores candidates against a concrete rubric via an independent cross-judge, picks a base, and borrows the best bits from the runners-up.
๐ Phase 2: Architecture and Planning (Before the Code Rot)
Once an idea survives the initial interrogation, it needs structuring. But not all work starts from the same place. Some initiatives are cross-functional, needing agreement between Product and Engineering on scope, milestones, and system design. Others are purely engineering-led problems where we already know we need to build something, but need to research the shape and plan the work.
My setup splits this into two distinct tracks: pdd for cross-functional
initiatives, and architect for engineering-led features.
Cross-functional alignment: pdd
When Product and Engineering need to agree before anyone touches code, I use
pdd (Project, Discovery, Design). It treats governance as a series of three
explicit, human-in-the-loop approval gates:
- Project (
project.md): Agrees on what the initiative actually is, why it matters, and when milestones should land. - Discovery (
discovery.md): Evaluates solution directions and trade-offs for a milestone without committing to implementation details. - Design (
design.md): Documents the approved system-level architecture thoroughly enough for Product, Engineering, and reviewers to sign off.
Unlike most agent skills that run through to the end autonomously, pdd stops
dead at each gate (Awaiting approval). It refuses to advance to Discovery
until Project is approved, and will not touch Design until Discovery is signed
off.
Crucially, design.md is not an implementation plan (plan.md). It answers
what system solution is being approved, not how an engineer will slice the pull
requests. Once Design is approved, pdd hands off directly to to-spec to
define the technical contracts. You do not run architect afterwards, because
doing so would pointlessly duplicate the discovery you just agreed upon.
Engineering-led coordination: architect
When an initiative is driven entirely by engineering, running through a
three-stage product governance dance is overkill. That is where architect
comes in.
Where pdd is a gated approval workflow for cross-functional consensus,
architect is an automated coordinator for engineering delivery. It chains
five phases together in sequence: bootstrapping project rules (agents-md),
deep research (research), writing the functional specification (to-spec),
adversarial stress-testing (grill-with-docs), and implementation planning
(to-plan).
If pdd is about deciding what to build with Product, architect is about
taking an engineering idea and autonomously generating the technical artefacts
needed to build it safely.
The engineering handoff: specs, plans, and tasks
Regardless of whether an initiative starts in pdd or architect, both tracks
converge on the same engineering delivery pipeline under
projects/<yyyy-mm-dd-slug>/:
to-spec: Generates a solid capability specification (spec.md) with user stories, acceptance criteria, and testing seams. Living specs stay validated in CI so contracts don’t rot.to-plan: Breaks the specification into vertical implementation slices (plan.md) with explicitBlocked-bydependency edges and PR groupings.to-tasks: Compiles a single plan slice just-in-time into a mechanical, TDD-shaped runbook (tasks.md) with verbatim code and assertions, avoiding upfront plan decay.
๐จ Phase 3: Building (Small, Mechanical Slices)
With tasks compiled, execution becomes fast and predictable.
next-task&next-slice:next-taskimplements and verifies the next item in the runbook, whilenext-sliceworks through an entire vertical plan slice in one go.conventions-*&go-testing: Enforces strict language conventions (conventions-go,conventions-python,conventions-sql, and others) and testing discipline (table-driven tests,t.Context(), bounded waits, public API testing, and zero unkeyed struct literals).unslop: Strips AI tells, buzzwords, puffery, and robotic cadence from documentation and prose to restore a clean, authentic human voice.cleanup: Runs a background audit hunting for AI-generated clutter, dead code, and unnecessary abstractions.precedent: Audits newly written code against existing conventions in the codebase, flagging any inconsistencies in naming, error handling, or API signatures.
๐ง Phase 4: Sceptical Review (Don’t Be a Pushover)
Reviewing code with AI works both ways: having agents review code, and critically evaluating the feedback agents give you.
code-review: Runs multi-dimensional reviews across parallel subagents (behaviour, security, reliability, maintainability) usingpi-subagentsto catch subtle bugs without blowing up the context window.is-it-safe: Rather than general reviews or speculative risk matrices, this runs an adversarial impact analysis answering one question: what is the worst credible outcome if this exact diff is merged? It uses an independent max-effort subagent pass to trace a concrete failure path (trigger, changed behaviour, blast radius) and test safeguards before returning a clear verdict (๐ขPROCEED, ๐กHOLD, ๐ดSTOP). It catches nasty blast-radius surprises so changes ship safely without relying solely on green tests.code-review-feedback&security-review-feedback: When an AI reviewer (or static analyser) flags an issue, you shouldn’t reflexively accept it. These skills force the agent to evaluate the claim with technical rigour. Is the vulnerability actually reachable? Is the suggested refactor introducing hidden complexity? If a suggestion is rubbish, reject it with proof.
๐ข Phase 5: Shipping Without the Drama
When the code is tested and clean, shipping is a deterministic, mechanical step.
branch: Cuts a feature branch using session context and standard naming.commit: Stages and groups files sensibly, enforcing titles that explain why the change matters rather than listing raw mechanical steps.draft-pr: Generates a concise pull request with clear Problem and Solution sections, consequence-driven titles, and load-bearing emoji.stacked-prs: Coordinates dependent PR chains with the officialgh-stackCLI extension, mapping vertical slices fromto-plandirectly into isolated, easily reviewable PR layers.bcp: Orchestrates branch creation, committing, and opening a PR (or submitting a stacked branch) in one command.
๐งญ Choosing the Right Analysis Skill
Different engineering problems call for different analytical lenses:
| Skill | Use when | Primary output |
|---|---|---|
perspectives |
Brainstorming or running a “what are we missing?” pass | Multi-perspective analysis |
decide |
Choosing between consequential engineering options | Durable decision memo / ADR |
consensus |
A complex design or implementation needs independent cross-model review and approval gates | Reviewed assessment or implementation with dissent preserved |
arena |
Non-trivial artefact where one attempt risks the wrong shape | Synthesised multi-model artefact |
precedent |
Ensuring new code matches existing codebase conventions | Divergence report citing peer patterns |
code-review |
Code or diff exists and defects must be identified | Verified findings across subagents |
is-it-safe |
Assessing the worst credible failure mode and blast radius before merge | Adversarial impact report with a PROCEED/HOLD/STOP verdict |
๐ Tight Feedback Loops with Crit
One of the biggest friction points with AI workflows is the review loop. Normally, you’re either squinting at terminal diffs trying to explain in chat which line needs changing, or you’re pushing half-baked branches up to GitHub just to use their pull request UI. Both options are clunky. Terminal diffs are annoying to comment on with precision, and pushing to GitHub drags remote latency and premature commits into what should be a fast local experiment.
This is where Crit fits in. Crit is a
lightweight, local review tool that runs in your browser. When an agent finishes
drafting a plan, generating a spec, or writing a chunk of code, I run crit (or
the agent triggers it via my crit skill). It opens an interactive review UI in
the browser where I can see the full diff, highlight specific lines, leave
inline comments, file-level notes, or general feedback, just like a GitHub PR
review, but completely local.
crit # branch diff against main
crit <plan-file> # review an implementation plan or spec
crit --pr <num|url> # fetch and review a GitHub PR locally
The real beauty is how it closes the loop with the agent. Crit stores review
feedback in a structured local JSON file. The agent reads that file, finds any
unresolved comments, fixes the code or plan, and replies directly to each
comment with what it changed. Once the edits are done, the agent re-runs crit
to trigger the next review round.
We can iterate through three or four review rounds locally in minutes, without
pushing a single commit upstream. And when everything finally looks right, crit
push can sync those local comments straight up to the GitHub PR review if
needed. It keeps the human firmly in the driving seat without breaking the flow.
๐งโ๐ซ Teaching with Slides (Beyond Code)
Engineering isn’t just churning out code. A good chunk of the job is explaining complex systems to peers, onboarding team members, or helping someone grasp an unfamiliar concept without overwhelming them.
That is where teach-with-slides
comes in. Instead of spitting out a dry wall of text or generic bullet points,
it builds a structured, beginner-friendly learning deck. It establishes a
proper learning arc, starting with a relatable hook, introducing the core
mental model, and breaking the topic down into digestible steps.
It also handles the presentation format depending on what I need: HTML for a quick browser deck, PPTX or Google Slides when it needs editing, or PDF for sharing. It keeps slides focused on a single idea, leans heavily on Mermaid diagrams to show relationships rather than describing them, and applies clean visual themes (a warm Claude-inspired palette or an informal Fastly-inspired style for colleagues).
๐ MCP & Wiring Up Context
Agents are only as useful as the context you feed them. I use a handful of MCP servers to bridge the gap between local code and the tools I use every day:
- Google Workspace MCP: Bundled locally in
mcp/google-workspace/(an unmodified build of upstreamgemini-cli-extensions/workspace). Gives the agent secure access to Calendar, Drive, Docs, Sheets, and Gmail via local OAuth. - Atlassian MCP: Connects to Jira and Confluence using the modern MCP
Streamable HTTP transport via
mcp-remotewith--transport http-only. - Language Servers (
gopls): Supplies real-time compiler diagnostics and symbol definitions directly to the agent. - Context7: Live documentation indexing and retrieval for up-to-date third-party libraries.
โน๏ธ NOTE
All sensitive endpoints and API keys are injected dynamically via 1Password
CLI templates (.claude.json.tmpl, .copilot/mcp-config.json.tmpl), ensuring
no secrets ever leak into version control.
๐ฐ Keeping Costs Sane
Running every simple command through top-tier frontier models is slow and expensive. My setup enforces a bit of financial and token discipline:
- Model Tiering: Mechanical tasks (searching files, drafting changelogs, running tests) default to fast, cheap models like Gemini Flash or Claude Haiku. Heavy reasoning models are kept for architecture, gnarly debugging, and grilling.
pi-subagents: An extension I built to run isolated subagents in the same process. Each subagent gets its own context window and tool allowlist, so a deep investigation costs the main session a single summary line instead of ten thousand tokens.model-stats: A skill that parses local logs across every harness I use (Claude Code, Pi, Codex, OpenCode, Gemini CLI, Copilot CLI) and renders an interactive HTML dashboard showing token consumption, spending, and reasoning effort by provider, model, and project. When a harness doesn’t log costs directly, it estimates them using LiteLLM pricing data.caveman: An ultra-compressed communication mode (~75% token reduction) for rapid back-and-forth debugging when full conversational prose is just in the way.
๐ Wrapping Up
I don’t think coding agents are going to replace engineers anytime soon. Equally, writing them off as useless gimmicks misses how much time they can save when you treat them properly.
If you let an agent write code without tests or boundaries, you’ll end up with unmaintainable junk. Wrap them in a sensible pipeline, make TDD non-negotiable, and demand proof for every claim, and they become genuinely useful.
If you want to borrow any of the skills or conventions, have a browse around the
agent-skills repo and tweak
them to suit your own workflow.