↓ Skip to main content
  1. Posts/

How I Run an Agentic AI Setup with OpenCode

·854 words·5 mins·
Table of Contents

I do not use one chatbot for coding. I run a small team of agents. One orchestrator receives my request, splits the work, and hands pieces to specialists. Shared rules keep each agent small and checkable. The whole setup lives in a Git repository and is deployed with Ansible.

This post maps the parts, shows how they connect, and lists what I learned the hard way.

The big picture
#

flowchart LR
  Me["Me"] --> Orch["Orchestrator"]
  Orch --> Spec["Specialist agents"]
  Orch --> Task["Task profiles"]
  Spec --> Tools["MCP tools"]
  Task --> Tools
  Rules["AGENTS.md rules"] -.-> Orch
  Rules -.-> Spec
  Skills["Skills"] -.-> Orch
  Plugins["Plugins"] -.-> Orch
  Repo["workstation-wsl repo"] -->|"Ansible deploys"| Home["~/.config/opencode"]
  Home --> Orch

The repo is the source of truth. Ansible copies the tracked config into my home directory, and OpenCode reads it from there.

Layers
#

LayerWhat it holdsWhere it lives
InstructionsGlobal rules and repo rulesAGENTS.md files
OrchestrationOrchestrator and specialist roles, model presetsoh-my-opencode-slim.jsonc
Task profilesquick, build, fast, deep, plus infra, incident, IaC, security, performance, automation, docsopencode.jsonc
ToolsContext7, GitHub, filesystem, Docker, Kubernetes, Atuinopencode.jsonc (MCP)
PluginsNotifier, quota, model discovery, orchestration, context pruning, observability, goals, skill creator, Ponytail, Tavilyopencode.jsonc (plugins)
SkillsReusable workflows: brainstorming, debugging, TDD, code review, worktrees~/.config/opencode/skills
Commandsreview, fix-test, commit (never pushes), pr draft, caveman styleopencode.jsonc (commands)
DeploymentProvisioning and repo command interfaceAnsible role, Makefile

Who does what
#

The orchestrator is the default agent. It plans and delegates. It does not do bulk searching or large edits itself.

sequenceDiagram
  participant Me
  participant O as Orchestrator
  participant E as Explorer
  participant F as Fixer
  participant V as Oracle
  Me->>O: Task
  O->>E: Find code and docs (parallel)
  E-->>O: Findings with file paths
  O->>F: Bounded change with scope and check
  F-->>O: Diff summary
  O->>V: Only for risky design or repeated failure
  V-->>O: Advice
  O-->>Me: Result and verification

The roles:

  • Orchestrator: plans, dispatches work in parallel, checks results.
  • Explorer: read-only search, file lookup, and library docs.
  • Fixer: bounded implementation, multi-file or mechanical edits.
  • Designer: all UI and UX work. The orchestrator never does design itself.
  • Oracle: escalation for architecture, risk, and debugging after two failed fixes.
  • Observer: reads images and PDFs, so media bytes stay out of the main context.
  • Council: three seats (alpha, beta, gamma) on different models. Their answers are synthesized into one view.
  • Review agents from the marketplace: documenter, janitor, paladin (security), arbiter (review), chronicler (docs), hunter (error paths), proctor (test sufficiency).

Rules that shape behavior
#

Rules load in a fixed order. Global rules come first, then the repo rules, then the agent’s own prompt and permissions.

flowchart TD
  G["Global AGENTS.md"] --> R["Repo AGENTS.md"]
  R --> A["Agent prompt and permissions"]
  A --> T["Task"]

The main rules are short:

  • Read before editing. Search with targeted grep or glob.
  • Make the smallest correct diff. No unrelated refactors.
  • Verify with the narrowest check first.
  • Use make targets as the only command interface.
  • Keep terminal output short (-s, --quiet, or | tail).
  • If an approach fails twice, change approach or escalate.
  • Ask one question only when the answer changes the outcome. Otherwise decide and state the assumption.

Two style skills sit on top: Ponytail pushes for the smallest change that fully works, and caveman keeps chat replies terse.

Model routing and failover
#

Each role has a model preset. Presets pick cheap, mid, or high-cost models per role. If a call fails, the plugin retries twice, then moves to the next model in the chain.

flowchart LR
  Req["Agent call"] --> M1["Primary model"]
  M1 -->|"fails twice"| M2["Next model in chain"]
  M2 -->|"fails twice"| M3["Next model in chain"]
  M3 --> Err["Report failure"]

Permissions and safety
#

  • Review and triage agents deny edits. Implementation agents allow them.
  • Atuin history access is denied by permission.
  • The filesystem tool is scoped to ~/code.
  • The commit command never pushes.
  • The OpenRouter key is set up during provisioning, with secret logging suppressed.
  • The npm config keeps engine-strict and prefer-offline off, so plugin updates do not fail.

Deployment
#

flowchart LR
  Git["Git repo sftp/.config"] -->|"Ansible"| Home["~/.config/opencode"]
  Ansible["opencode.yml role"] -->|"installs"| UI["OpenChamber and key service"]
  Make["Makefile"] -->|"make lint and checks"| Git

Ansible deploys the tracked config. The Makefile holds the lint, syntax, and check targets, and the agents are told to verify through them.

Lessons
#

  • Two copies drift. The tracked and installed configs differ, for example in the default model. Deploy from the repo only, and never edit the home copy by hand.
  • Agent permissions override global ones. An allow in an agent’s config beats a global deny. I removed shell allows from agents for this reason.
  • Strict npm settings break plugins. engine-strict=true makes updates fail on engine mismatches. prefer-offline=true misses newly published versions.
  • Some plugins are off. The metrics plugin is commented out because of a TUI compatibility issue.
  • Model names change. Keep presets in one file so a swap touches one place.

What I would keep and cut
#

Keep the orchestrator, the rule files, and the Makefile interface. These do most of the work. Cut any plugin or agent that I have not used in a month. Every extra agent is one more thing to route, permission, and debug.

Related