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:
- Nobody owns the config. It lives in home directories, so there is no review, no history and no way to roll back.
- MCP servers drift. One laptop runs
npx some-mcpat whatever version was latest that day, another one is three versions behind. - Secrets end up in the wrong place. The Jira or Atlassian token has to go somewhere, and "somewhere" quickly becomes a plaintext JSON file.
- Teams want different things. The platform team wants a
devopsagent 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 --v3That'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 pinsEvery 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:
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:
{ "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 render [team] --out <dir> # render only
kirokit test [team] # diff against the goldens (CI)
kirokit update [team] # regenerate goldens after a template changeChange 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:
externalSkills:
- source: https://github.com/anthropics/skills.git
ref: <commit-sha>
path: skills/pdfkirokit 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:
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_BACKUPConclusion
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.



