Tools

kirokit: Sharing Kiro CLI config across teams

A small Go CLI that renders per-team Kiro CLI agents, steering and skills from templates, pins MCP server versions centrally and keeps secrets out of every committed file.

Oct 16, 2026 · 7 min read · 1,359 words

Photo generated by claude

Introduction

We've all been there: one person on the team gets a really good agent setup in their AI coding CLI. The right prompt, a few MCP servers, some rules about what the agent may and may not do. Two weeks later, a colleague asks for it, you zip up a folder from ~/.kiro, and from that moment on you have two diverging copies and no idea which one is the good one.

In this post, I want to share kirokit, a small Go CLI and repository layout I built to fix exactly this for Kiro CLI v3.

Note: this works for several projects I worked for. It works for me, but it's far from complete. Feel free to contribute. If you want a more mature version, please take a look at apm from Microsoft. I preferred to keep it lean for now.

Now let's go into the details.

The problem

Kiro CLI reads its agents, prompts, hooks, steering docs, and skills from $KIRO_HOME (~/.kiro by default). That is great for one person. For several teams, it gets messy quickly, and for me it always starts with these four things:

  1. Nobody owns the config. It lives in home directories, so there is no review, no history and no way to roll back.
  2. MCP servers drift. One laptop runs npx some-mcp at whatever version was latest that day, another one is three versions behind.
  3. Secrets end up in the wrong place. The Jira or Atlassian token has to go somewhere, and "somewhere" quickly becomes a plaintext JSON file.
  4. Teams want different things. The platform team wants a devops agent with Jira access, the data team wants a Snowflake MCP server and no shared steering at all. One shared folder doesn't work; one folder per person doesn't scale.

The solution

kirokit treats the Kiro config as source code. Each team owns a directory of templates in a git repository, and the CLI renders them into the exact layout Kiro expects.

brew install --cask mavogel/tap/kirokit
kirokit version
 
git clone https://github.com/mavogel/kirokit.git
cd kirokit
 
kirokit install platform-team
kiro-cli chat --agent devops --v3

That's the whole user experience. Everything interesting happens in the repository behind it.

Teams own templates

The layout is boring on purpose:

teams/<team>/manifest.yaml
teams/<team>/agents/<agent>/agent.json.tmpl
teams/<team>/agents/<agent>/env/secrets.enc.yaml   # optional, SOPS-encrypted
teams/<team>/hooks/*.json.tmpl
teams/<team>/prompts/*.md.tmpl
teams/<team>/skills/<skill>/SKILL.md.tmpl
teams/<team>/steerings/*.md.tmpl
 
global/steerings/*.md          # shared docs a team can opt into
env/mcp-versions.yaml          # central MCP version pins

Every source file has a double extension like agent.json.tmpl. The renderer finds them with a **/*.tmpl glob, strips the .tmpl and writes the result to Kiro's flatter layout, so agents/devops/agent.json.tmpl becomes agents/devops.json. Prompts are a nice bonus: Kiro lists every file in prompts/ as a slash command, so a template like create-steering.md.tmpl shows up as /create-steering after the install.

Duplication between teams is expected and fine. There are two worked examples in the repo (platform-team and data-team), and kirokit onboard <team> scaffolds a new one.

Pinned MCP versions

All MCP server versions live in one file:

env/mcp-versions.yaml
mcp-remote: "0.14.3"
context7-mcp: "4.3.0"

An agent template asks for its version with {{ mcpVersion "context7-mcp" }}. If the key doesn't exist, the render fails and names the missing key and the file. Bumping a pin in one place then shows you which teams' output changes. I let Renovate open those bump PRs, so the pins don't rot.

Secrets without plaintext

This was the part I cared about most. A token never appears in a template, in rendered output, or in a test fixture. Instead, each agent has its own SOPS-encrypted secrets.enc.yaml (ciphertext, safe to commit), and the MCP server is launched through sops exec-env:

"atlassian": {
  "command": {{ sopsCommand }},
  "args": {{ sopsArgsJSON (printf "%s/kirokit-secrets/platform-team/devops/secrets.enc.yaml" .KiroHome) "npx" "-y" (printf "mcp-remote@%s" (mcpVersion "mcp-remote")) "https://mcp.atlassian.com/v2/mcp" "--header" "Authorization: ${ATLASSIAN_AUTH}" }}
}

SOPS decrypts the file when the MCP server starts and sets the keys as environment variables for that process. I went this way because Kiro CLI's own ${VAR} substitution wasn't reliable for me. Every team also gets its own age key, so the platform team's key can't decrypt the data team's secrets.

Permissions in the template

Since the agent config is a template, the guardrails are reviewed like any other code. The devops agent for example may read everything, write only to /tmp, has to ask before calling the Atlassian tools, and has a hard deny on rm *, force pushes, pushes to main and branch deletion:

devops agent permissions
{ "capability": "shell", "match": ["rm *"], "effect": "deny" },
{ "capability": "shell", "match": ["git push --force*", "git push -f*"], "effect": "deny" },
{ "capability": "shell", "match": ["git push * main", "git push * main *"], "effect": "deny" }

On top of that, a team can opt into a shared steering such as security-baseline. It is added to the resources of every agent of that team, and only those, because it's rendered to kirokit-steerings/<team>/ and not into Kiro's auto-loaded steering/ folder.

Golden files catch drift

Rendering is deterministic: kirokit renders with a fixed /kiro-home sentinel, so the output is the same on every machine. The committed result lives in testdata/golden/<team>/, and CI compares it byte for byte.

kirokit commands for golden files
kirokit render [team] --out <dir>   # render only
kirokit test [team]                 # diff against the goldens (CI)
kirokit update [team]               # regenerate goldens after a template change

Change a template, run kirokit update, and the golden diff in the pull request shows exactly what each agent will look like after the merge. For me, that review step is the biggest win, because nobody has to guess what a template change does. go test additionally runs kiro-cli agent validate on the rendered agents when a logged-in kiro-cli is available.

Skills from other repositories

Teams can also pull in skills from other git repositories, pinned to a ref:

external skills configuration
externalSkills:
  - source: https://github.com/anthropics/skills.git
    ref: <commit-sha>
    path: skills/pdf

kirokit skills fetch <team> copies the skill byte for byte into teams/<team>/external/skills/ and writes a lock file with the resolved commit and a content hash. Fetching is the only step that touches the network. render, test, install and sync work offline, and they fail if the vendored files and the lock disagree. So a hand-edited skill doesn't slip through.

Install, back up, sync

kirokit install <team> renders with your real $KIRO_HOME and copies the files there. kirokit uninstall <team> removes exactly what that install wrote, tracked in a manifest, and leaves other teams and Kiro's own data alone. Before an install overwrites anything, the affected folder is copied to something like 20261015-101530-agents.backup.

To keep everyone current, there is kirokit sync. It pulls the config repository, optionally checks out the newest v* tag, installs, and removes files the team stopped shipping. scripts/kirokit-sync-setup.sh registers it as a launchd agent on macOS or a systemd user timer on Linux, every four hours by default.

Try it without touching your setup

Kiro respects KIRO_HOME, so you can test kirokit in a throwaway directory:

testing kirokit in a throwaway directory
git clone https://github.com/mavogel/kirokit.git
cd kirokit
 
export KIRO_HOME_BACKUP=$KIRO_HOME
export KIRO_HOME=$(mktemp -d)
 
# add a new external skill to the platform-team manifest
cat >> teams/platform-team/manifest.yaml <<'EOF'
 
externalSkills:
  - source: https://github.com/anthropics/skills.git
    ref: dbd4588f9e1033efb41dad4bef2f7947c8993d44
    path: skills/frontend-design
EOF
 
# fetch and update the platform-team with the new external skill
kirokit skills fetch platform-team
kirokit update platform-team
 
# install the updated platform-team in tmp KIRO_HOME
kirokit install platform-team
 
# run the devops agent in chat mode
kiro-cli chat --agent devops --v3
 
# and see the frontend-design skill is present...
 
rm -rf $KIRO_HOME
export KIRO_HOME=$KIRO_HOME_BACKUP

Conclusion

My rule of thumb: as soon as a second person needs your agent setup, it belongs in git, not in a home directory. Templates give each team room to differ, the central pins and golden files keep the differences visible, and SOPS keeps the tokens out of the picture.

Personally, I'd start with one team, one agent, and the golden tests, then add secrets and sync once the first colleague asks for the config. If you try it, I'd like to hear what breaks. Happy rendering!

This post was written with AI assistance and verified plus enhanced by a human.

More from the blog

Keep reading - related notes from recent engagements.

Tools

Running Gitea Locally with OpenTofu

A pinned Gitea 1.27 on OrbStack's Kubernetes, provisioned end to end with OpenTofu: Gateway API instead of Ingress, and a CI runner that reaches the host Docker daemon without Docker-in-Docker.

Ready to ship faster on AWS?

Tell us what you are building. We will map the fastest safe path to production and the platform to keep it there.

Notes from production

Occasional, no-fluff writing on AWS, DevOps, and running platforms that stay up. No spam, unsubscribe anytime.

Practical, not promotional
Real lessons from real engagements - architecture, automation, and incident post-mortems.
No spam
A few emails a year at most. Your address is never shared or sold.