Every team has that set of boring tasks nobody enjoys but everybody has to do the exact same way every time: open a PR with the right title format, name the branch correctly, build the changelog, link the work item. These are low-intellectual-value, high-attention-cost chores — and worse, any deviation from the standard becomes noise during review.
I decided to tackle this differently: instead of writing yet another giant bash script, I built specialized AI agents that encapsulate these workflows. In this article I'll show how I structured that setup using the Kiro CLI, with a pattern that cleanly separates configuration, knowledge, and safety rules.
I'll use my own agents as the example — with internal names abstracted away — but the pattern works for any team.
The problem
In my day-to-day, I repeated two workflows several times a day:
- Opening a Pull Request: create the branch in the right format, commit with the correct convention, infer the target branch, open the PR with a standardized title and description, and link the work item.
- Closing a release package: find the already-completed PRs for a work item, generate the changelog, commit it, and open a release PR against the right branch.
None of these steps is hard. The problem is that every one of them has details — and a forgotten detail means rework. Automating with a pure script would be fragile, because many of the decisions depend on context (which branch, which title, which target).
AI agents are great precisely in that gray zone: they follow rules, but they interpret context.
The core idea: separate configuration, knowledge, and rules
What helped me the most was not throwing everything into one giant prompt. Instead, I split each agent into four layers, each in its own file:
.kiro/
├── agents/ # Configuration: which tools the agent is allowed to use
├── prompts/ # Identity: who the agent is and its fixed context
├── steering/ # Guardrails: what it must NEVER do
├── skills/ # Knowledge: the step-by-step for each task
└── settings/ # Integration with external tools (via MCP)
The key insight is that each layer has a single responsibility:
- Agent = the contract (allowed tools, shortcut, welcome message)
- Prompt = the identity (context that never changes)
- Steering = the limits (non-negotiable prohibitions)
- Skill = the manual (how to execute each step, with examples)
Splitting it this way brings a huge benefit: skills become reusable across agents. The "create commit" skill is the same for the agent that opens PRs and the one that closes releases.
Layer 1 — The agent (configuration)
The agent's config file is lean. It states what the agent can do, not how. Here's an example (abstracted):
{
"name": "open-pr",
"description": "Agent that opens Pull Requests: creates a branch, commits, opens the PR and links the work item.",
"prompt": "file://./prompts/open-pr.md",
"includeMcpJson": true,
"tools": ["shell", "read", "write", "grep", "glob", "@git-provider"],
"allowedTools": [
"shell",
"read",
"write",
"@git-provider/create_pull_request",
"@git-provider/create_branch",
"@git-provider/link_work_item"
],
"resources": [
"skill://.kiro/skills/commit/SKILL.md",
"skill://.kiro/skills/create-branch/SKILL.md",
"skill://.kiro/skills/open-pr/SKILL.md"
],
"keyboardShortcut": "ctrl+shift+p",
"welcomeMessage": "Give me the work item ID or describe the feature. I'll handle the rest."
}
Two important points here:
-
allowedToolsis an explicit allowlist. The agent can only call exactly the tools I listed. That's security by design: it won't accidentally call a destructive tool I never authorized. -
resourcesinjects the skills. The agent loads detailed instructions on demand instead of carrying everything all the time.
Layer 2 — The prompt (identity and fixed context)
The prompt defines who the agent is and which context never changes. This is where I "anchor" the agent so it doesn't keep asking the obvious every time.
You are an agent specialized in opening Pull Requests for the
team's repository.
## Fixed Context
- Git provider: <configured via MCP>
- Project / repository: <fixed, injected by configuration>
- Default source branch: `main`
## Operating Rules
- ALWAYS use the fixed project and repository — NEVER ask the user
- Infer the target branch from the work item context
- Follow the branch and commit conventions defined in the skills
## What NOT to do
- Do NOT ask for project or repository — they are fixed
- Do NOT push directly to protected branches
Notice the "Rules" + "What NOT to do" pattern. Telling the agent what not to do is just as important as telling it what to do. It dramatically reduces unpredictable behavior.
Tip: data that must not leak (internal IDs, GUIDs, URLs) stays out of public articles/docs and is injected via configuration or MCP. Never put that in the body of a skill that lands in an open repository.
Layer 3 — Steering (non-negotiable guardrails)
This is the layer that lets me sleep at night. Steering lists absolute prohibitions, independent of any instruction the agent receives.
# Open PR — Guardrails
## Prohibitions
- NEVER force push
- NEVER push directly to protected branches
- NEVER create a PR without at least 1 commit on the branch
- NEVER proceed if git shows unresolved conflicts
## Mandatory Confirmations
- ALWAYS show the summary (branch, commits, target, title) before opening the PR
- ALWAYS confirm if there's any doubt about the target branch
## Failure Behavior
- If the push fails → show the error and suggest an action (never force)
- If the target branch doesn't exist → ask the user
The distinction between prompt and steering is intentional: the prompt is the personality (it can have nuance), the steering is the law (no exceptions). Even if the user says "just force push it," the guardrail holds.
Layer 4 — Skills (reusable knowledge)
Skills are the heart of the setup. Each one is a short document that teaches one procedure, with a format and examples. The commit skill, for instance, defines the full convention:
# Responsibility
Create standardized commits.
## Format
<type>(<scope>): <emoji> <short description>
## Procedure
1. Run `git status --short`
2. Analyze the paths to determine type and scope
3. Group into logical commits
4. Stage selectively (never `git add .`)
5. Commit with the formatted message
## Examples
feat(module-a): ✨ add product tag component
fix(module-b): 🐛 correct price display
refactor(shared): 🔨 simplify item props
The strong point: the same commit skill is used by both the PR agent and the release agent. I wrote it once and reused it everywhere. When the convention changes, I edit a single file.
My second agent — the release closer — is basically skill orchestration:
Receives the work item ID
→ finds the already-completed PRs
→ switches to the right branch
→ generates the changelog
→ uses the commit skill
→ uses the open-pr skill to open the release PR
→ links the work item
In other words: a complex agent emerges from composing simple skills. That's far easier to maintain than a monolithic prompt.
Layer 5 — Integration via MCP
For the agent to actually open PRs and fetch work items, it needs to talk to the git provider. I do this via MCP (Model Context Protocol), which exposes external operations as tools the agent can call.
{
"mcpServers": {
"git-provider": {
"command": "npx",
"args": ["-y", "<provider-mcp-package>", "--arg", "value"],
"env": {
"PROVIDER_ORG_URL": "<org-url>",
"PROVIDER_DEFAULT_PROJECT": "<project>",
"PROVIDER_DEFAULT_REPOSITORY": "<repo>"
}
}
}
}
MCP is what connects the "brain" (the agent) to the "hands" (the operations on the git provider). And combined with the agent's allowlist, I control exactly which of those operations are available.
Layer 6 — Onboarding docs
Finally, I keep a short doc per agent explaining what it is and how to invoke it. It's what I hand to anyone new on the team:
# `open-pr` Agent
## How to invoke
- Shortcut: Ctrl+Shift+P
- Or: "Open a PR for work item 123" / "Commit and open a PR"
## Flow
User provides a work item → fetch context → create branch →
commit → push → open PR → link work item → return the link
## Where the rules live
| Topic | File |
|---------------------|-----------------------------|
| Branch convention | skills/create-branch |
| Commit convention | skills/commit |
| PR rules | skills/open-pr |
| Guardrails | steering/open-pr |
The result in practice
Once this setup entered my workflow, opening a PR became a single sentence: "open a PR for work item X." The agent infers the branch, commits in the right format, opens the PR with the correct title and description, and links the work item — always the same way, without me having to remember each detail.
And looking at the repository's commit history, you can see the convention being followed consistently: type, scope, emoji, and a short English description, commit after commit. That consistency is exactly what I wanted — and it no longer depends on my memory on a tired day.
What I'd take to any project
If I had to boil the lessons down into reusable principles:
- Separate configuration from knowledge. The agent says what it can do; the skill says how to do it.
- Guardrails are their own layer. Prohibitions shouldn't be mixed with normal instructions.
- Small, reusable skills. A complex agent is a composition of simple skills.
- Always allowlist tools. Security by design, not by trust.
- Say what NOT to do. It reduces unpredictable behavior more than any positive instruction.
- Keep sensitive data out of skills. Inject it via configuration/MCP, never in versioned text.
In the end, I didn't just automate tasks — I standardized decisions. And that, more than the time saved, is what actually changed my workflow.
If you also find yourself repeating the same Git steps over and over, this pattern is worth a try. Start with a single skill, like the commit one, and compose from there.
🇧🇷 Versão em português: Como transformei tarefas repetitivas de Git em agentes de IA com o Kiro CLI
Top comments (0)