Skip to content

feat: add dashboard authoring for custom Agent Templates - #2023

Closed
RohanK6 wants to merge 1 commit into
kirodotdev:mainfrom
RohanK6:feat/agent-template-authoring
Closed

feat: add dashboard authoring for custom Agent Templates#2023
RohanK6 wants to merge 1 commit into
kirodotdev:mainfrom
RohanK6:feat/agent-template-authoring

Conversation

@RohanK6

@RohanK6 RohanK6 commented Aug 7, 2026

Copy link
Copy Markdown
Contributor

Problem

The Agent Templates surface is half of a capability model it cannot complete. A crew binds to an agent template and inherits everything from it — tools, MCP servers, skills, guardrails — and the dashboard can inspect installed templates and edit their model and skill mappings. But it cannot create one. A user who needs two crews with different capability sets has to leave Kiro Crew and hand-author a JSON file under ~/.kiro/agents/, guessing at the schema the inspector already renders.

Closes #1829.

Fix

A Create template action on Agent Capabilities → Agent Templates (and an empty-state entry point when no templates are installed) opens a structured authoring dialog over the same agent model the inspector reads. One POST /api/agents/installed validates the complete draft and writes the new user-owned spec atomically.

End-to-end flow

Create template button ──► AgentTemplateCreator dialog (one complete draft, nothing saves early)
        │                        │  name/description · model · system prompt
        │                        │  skill catalog toggles · tool chips (+ per-tool auto-approve)
        │                        │  inline MCP server rows · resources · denied commands
        │                        ▼
        │                POST /api/agents/installed
        │                        │
        │                        ├─ _build_template_spec() ── field-naming 400s
        │                        │    name charset == file stem charset (no traversal)
        │                        │    reserved names refused · per-field shape validation
        │                        │    mcpServers allowlist: command/args/env/timeout only
        │                        │
        │                        ├─ config lock ── duplicate identity check across ALL specs
        │                        │    (a package file pkg--foo.json naming "foo" claims the name)
        │                        │
        │                        ├─ apply_skill_mapping() ── catalog keys → skill:// resources
        │                        │    through the ENUMERATED catalog (unknown key ⇒ nothing written)
        │                        │
        │                        └─ atomic_write ~/.kiro/agents/{name}.json ── 201
        ▼
list refetch ──► created template selected in the inspector ──► visible in Crew template selector

Design decisions

  • Stem equals spec name. Discovery classifies {name}.json whose name matches the stem as user-owned (builtin). Framework files (kirocrew.json, …) and package files (pkg--agent.json) keep their existing ownership protections untouched; reserved names are refused outright.
  • Skills go through the catalog, never through paths. The dialog collects catalog keys; the backend resolves them with the same apply_skill_mapping the Skills editor uses, so the only skill:// paths ever written are ones the enumeration discovered. Free-form resources accept file:// URIs only — a hand-typed skill:// cannot bypass the boundary.
  • Rejections keep the draft. Every validation error carries code + field; the dialog surfaces the message on the named field without discarding anything typed. Duplicate names are also refused client-side before spending a request.
  • One creation model, reusable. The dialog is a standalone component fed by the page's existing queries (models, skills catalog, MCP probe), so a future edit/clone flow composes with it rather than adding a second representation of the schema — and it stays out of the way of the feat: redesign Agent Templates as a two-pane inspector #1346 inspector redesign.

Screenshots

All data below is synthetic fixture data from the capture harness (website/scripts/capture-agent-template-create.mjs — real built SPA, network stubbed).

Entry point — Create template button in the Templates roster (and the empty-state when none are installed) entry
Empty dialog — identity, model, prompt, skills, tools, MCP servers empty
Duplicate name refused client-side before any request duplicate
Complete draft — mapped skills, fs_read auto-approved (green shield), inline MCP server feeding an @release-notes mount suggestion, guardrails draft
After create — new template in the list and selected in the inspector with everything the form authored created

Testing

  • test/test_agent_template_create.py — 28 tests in three layers: VALIDATE (_build_template_spec field rules, unsafe/reserved names, field-naming errors), WRITE (aiohttp-level: duplicate filename AND duplicate spec-name conflicts, unknown skills write nothing, catalog mapping lands in resources, deniedCommands → toolsSettings), PROTECT (reserved names, non-object bodies).
  • website/src/test/AgentTemplateCreator.test.tsx — 10 tests: client-side name validation and duplicate refusal, single-POST payload shape (empty sections stay off the wire), shield toggle → allowedTools, tool removal cleanup, MCP rows with space-split args, server field-error mapping that keeps the draft, 409 conflict surfacing, probed @server suggestions.
  • Full local gate sweep: complete vitest run (9,798 passed; one pre-existing unitLiterals 15s timeout under parallel load passes standalone), tsc -b, npm run build, eslint 0 errors under the warning ratchet, i18n master check + diff-scoped strings gate vs origin/main, locale style tests (bn/fr/hi/zh-CN informal register), docs-lint, backend isort/black/flake8 + pytest including the error-code contract.
  • E2E: the capture harness drives the real built SPA through the whole flow — open dialog, hit the duplicate-name rejection, author a complete draft, create, and land on the selected inspector view — with zero page or console errors.

i18n

39 new keys across pages.agentsPage and a new components.agentTemplateCreator namespace, translated in all 10 target catalogs (+ regenerated en-XA), with a context-sidecar entry for the ≤3-char "Add".

@RohanK6
RohanK6 requested a review from a team August 7, 2026 12:34
@RohanK6
RohanK6 requested a review from a team as a code owner August 7, 2026 12:34
@github-actions github-actions Bot added fork Pull request from a fork (external contributor) readiness: action required A blocking check or review needs attention readiness: checking Automated validation is still running and removed readiness: action required A blocking check or review needs attention readiness: checking Automated validation is still running labels Aug 7, 2026
@RohanK6
RohanK6 force-pushed the feat/agent-template-authoring branch from 9247585 to 9593a19 Compare August 7, 2026 13:33
@github-actions github-actions Bot added readiness: checking Automated validation is still running and removed readiness: action required A blocking check or review needs attention labels Aug 7, 2026
@github-actions

github-actions Bot commented Aug 7, 2026

Copy link
Copy Markdown
Contributor

GPT 5.6 Review (fork) — ⚠️ review incomplete

Reviewed 3d97b792d5573adb0c5377be2d1fd26c25b323be via the fork AI-review pipeline; updated in place on each push.

No completed GPT verdict for this commit; see the Fork GPT 5.6 Review job logs.

@github-actions

github-actions Bot commented Aug 7, 2026

Copy link
Copy Markdown
Contributor

UX Review (Fable 5, fork) — ⏭️ skipped

Revision 3d97b792d5573adb0c5377be2d1fd26c25b323be touches no user-facing surface (no changes under website/ or committed screenshots), so the UX review was skipped. Advisory — does not block merge.

@github-actions

github-actions Bot commented Aug 7, 2026

Copy link
Copy Markdown
Contributor

Design Review (Fable 5, fork) — ⚠️ could not complete

The design review did not produce a verdict for 3d97b792d5573adb0c5377be2d1fd26c25b323be (the model call errored or returned no verdict header). See the Fork Design Review job logs. Advisory — does not block merge.

@github-actions

github-actions Bot commented Aug 7, 2026

Copy link
Copy Markdown
Contributor

Opus 4.8 Review (fork) — ⚠️ review incomplete

Reviewed 3d97b792d5573adb0c5377be2d1fd26c25b323be via the fork AI-review pipeline; updated in place on each push.

No completed Opus verdict for this commit; see the Fork Opus 4.8 Review job logs.

@RohanK6
RohanK6 force-pushed the feat/agent-template-authoring branch from 9593a19 to 576dfc5 Compare August 7, 2026 14:08
@github-actions github-actions Bot added readiness: action required A blocking check or review needs attention readiness: checking Automated validation is still running and removed readiness: checking Automated validation is still running readiness: action required A blocking check or review needs attention labels Aug 7, 2026
@RohanK6
RohanK6 force-pushed the feat/agent-template-authoring branch from 576dfc5 to 1515920 Compare August 7, 2026 15:22
@github-actions github-actions Bot added readiness: checking Automated validation is still running readiness: action required A blocking check or review needs attention merge conflict Branch has merge conflicts with its base — author must resolve before merge and removed readiness: action required A blocking check or review needs attention readiness: checking Automated validation is still running labels Aug 7, 2026
@RohanK6
RohanK6 force-pushed the feat/agent-template-authoring branch from 1515920 to b0d695f Compare August 7, 2026 16:09
@github-actions github-actions Bot removed the readiness: action required A blocking check or review needs attention label Aug 7, 2026
@github-actions github-actions Bot added readiness: checking Automated validation is still running and removed readiness: action required A blocking check or review needs attention labels Aug 7, 2026
@RohanK6
RohanK6 force-pushed the feat/agent-template-authoring branch from 0733cfa to 925e1ac Compare August 7, 2026 22:08
@github-actions github-actions Bot added readiness: action required A blocking check or review needs attention readiness: checking Automated validation is still running and removed readiness: checking Automated validation is still running readiness: action required A blocking check or review needs attention labels Aug 7, 2026
@RohanK6
RohanK6 force-pushed the feat/agent-template-authoring branch from 925e1ac to 7c289ee Compare August 7, 2026 22:31
@github-actions github-actions Bot added readiness: action required A blocking check or review needs attention readiness: checking Automated validation is still running and removed readiness: checking Automated validation is still running readiness: action required A blocking check or review needs attention labels Aug 7, 2026
@RohanK6

RohanK6 commented Aug 8, 2026

Copy link
Copy Markdown
Contributor Author

Responding to the advisory (non-blocking) items from the UX and Design reviews on 6ab4ab32, in lieu of further revisions — all blocking findings across GPT/Opus are resolved and CI is green.

UX — Watch

Pending tool draft lost on submit. Valid catch, and the smallest of the two fixes proposed (auto-add a valid non-empty toolDraft on Create) is the right one. It is deliberately deferred rather than folded in here: this PR has been minimized to the create-only core, and the same draft-commit semantics question applies to the MCP args/name fields, so it belongs in one coherent pass with the edit flow (below) rather than as a one-off on this diff.

Shield discoverability. Agreed the hover-only InfoTip under-serves first-time users. Promoting the sentence into the visible helper line beside "Leave empty to use the default toolset." is a one-line change that will ride along with the follow-up above.

UX — Suggestions

  • Tooltip mechanism leak ("Mapped as skill:// resources"): the mechanism mention is intentional — hand-authors of ~/.kiro/agents/*.json need to know the mapping IS skill:// entries so they can reconcile dialog-created templates with hand-written ones (the docs section this PR adds relies on that vocabulary). Happy to trim if maintainers prefer the plain phrasing.
  • Suggestion cap slice(0, 12) with no overflow cue: acknowledged; a "+N more" cue is a good polish item for the follow-up. The full set remains reachable by typing (free-text covers everything), so nothing is unreachable today — only undiscoverable.

Design — Watch

Bespoke secret screening in the handler. Two parts to this:

  • Location: agreed in principle — the value-shape/key-name predicates belong in kiro_crew.security as shared helpers. Kept local in this PR to avoid growing the shared security surface inside an already-large feature diff; the extraction is mechanical (the predicates are pure functions with a pinned test suite, including an FE/BE regex drift-pinning test) and is a clean standalone follow-up. Note the handler already delegates the authoritative checks to shared code (is_sensitive_path, redact_credentials); the local layer only adds template-specific key/flag semantics.
  • "Guards inputs the dialog can't produce": the dialog does expose env-free MCP rows, but POST /api/agents/installed is a public dashboard API and the whole review history of this PR (app-token gating, KIROCREW_HOME re-anchoring, symlink vetting) treats direct-API callers as first-class threat surface. "They could write the JSON by hand" is true but irrelevant to the endpoint's contract: nothing the endpoint persists may contain a credential, whichever client sent it.
  • False positives hard-block with no override: by design — fail-closed matches the platform posture, and the $VAR/${VAR} reference form plus metadata-suffix exemptions (_FILE, _URL, --token-file, …) provide the sanctioned escape hatch for every legitimate case raised so far (--password-store passes: STORE is a metadata suffix).

Create-without-edit half loop. Correct, and named in the PR description as the scope cut: create-only ships first, edit/clone is the immediate follow-up. Until then the dead-end is mitigated by the inspector view making the written JSON visible right after create.

Design — Suggestion

Hoist predicates into kiro_crew.security — agreed, tracked as the same follow-up as the first Watch item above.

@iamwhatever iamwhatever left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Very cool, could you please also handle concerns raised in design and UX reviews? If not reasonable, please leave comments to push back.

@RohanK6

RohanK6 commented Aug 8, 2026

Copy link
Copy Markdown
Contributor Author

Thanks for the review! I went through every UX and Design item — I'd like to push back on folding them into this PR, with reasoning per item. Happy to reverse on any of these if you'd prefer them in this diff.

The common thread: this PR is deliberately scoped to the create-only core. The remaining items are either dialog polish that belongs in the edit-flow fast-follow, or a refactor that's easier to review as its own small diff than folded into an already-large feature commit. All of the deferred work is now tracked in #2255.

UX — pending tool draft lost on submit. Real catch, and auto-adding a valid toolDraft on Create is the right fix. But the identical draft-commit question applies to the MCP server name/args fields — fixing only the tools field ships inconsistent submit semantics. I'd rather do one coherent pass across all draft fields in the edit-flow follow-up than a partial fix now.

UX — shield auto-approve discoverability. Agreed. Promoting the InfoTip sentence to the visible helper line is a one-liner that rides with the follow-up above (it touches the same helper-line block the toolDraft fix restructures).

UX — suggestion cap with no overflow cue. Polish, not a gap: every tool remains reachable by typing (free-text covers the full set), so nothing is lost — only undiscoverable. "+N more" cue queued for the follow-up.

UX — tooltip "skill://" mechanism leak. Intentional: the docs section this PR adds teaches hand-authors that dialog skill mappings ARE skill:// entries in ~/.kiro/agents/*.json, so they can reconcile dialog-created and hand-written templates. Dropping the mechanism from the tooltip would orphan that vocabulary. Will trim if you disagree.

Design — secret predicates living in the handler. Agreed on the destination (kiro_crew.security), and the move is mechanical — the predicates are pure functions with a pinned test suite, including an FE/BE regex drift-pinning test. But it's a zero-behavior-change refactor: as a standalone PR it's a five-minute review; folded in here it grows an already-large diff without changing what the code does. Note the authoritative checks already live in shared code (is_sensitive_path, redact_credentials) — the handler layer only adds template-specific key/flag semantics.

Design — create-without-edit half loop. This is the named scope cut in the PR description: create-only ships first, edit/clone is the immediate follow-up (where the three UX items above land). Until then the inspector view shows the written JSON right after create, so the dead-end is visible rather than silent.

If you're good with this split, the deferred items are tracked in #2255 — the edit-flow fast-follow carries the toolDraft auto-add, shield helper-line promotion, "+N more" cue, and the security.py predicate hoist.

@RohanK6

RohanK6 commented Aug 8, 2026

Copy link
Copy Markdown
Contributor Author

Re: the review's blocking finding on 431230f8 — "path validation is vulnerable to post-creation symlink replacement" (benign path passes validation → parent later replaced with a symlink to ~/.ssh → agent startup reads credentials).

I'd like to push back on this one — it's a genuine false positive for this layer, for three reasons:

1. It's a consumption-time TOCTOU, which no authoring-time check can close. The validation runs when the template is created; the file is read when the agent starts, arbitrarily later. Between those two moments an attacker who already has write access to the user's home directory can swap any referenced path for a symlink — that is true of every file:// reference kiro-cli consumes, however it was authored. Adding more validation in the create handler cannot secure a path that is mutated after the check returns; the only real defense is at the point of consumption (kiro-cli resolving + re-checking the path when it actually opens it), which is outside this PR's surface.

2. The endpoint is not the trust boundary here. The same template can be hand-written to ~/.kiro/agents/{name}.json with no API involved. An attacker who can plant a symlink under ~ to redirect a resource can equally just write the JSON directly. So gating the creation API changes nothing about the threat — the capability to reference a local file is the feature, and the file's integrity is the user's own filesystem's concern.

3. The prescribed fix removes the feature. "Reject file:// prompts/resources here" would delete exactly what #1829 asks for — steering-file globs and prompt references are the point of the dialog (the docs section this PR adds documents them). We'd be shipping a template creator that can't reference the files templates are meant to reference.

What the PR does do at authoring time is the appropriate, in-scope hardening: reject sensitive literal targets (is_sensitive_path), reject .. traversal, reject wildcard globs in dialog input, and screen credential-shaped env/args. That closes the authoring-time attack surface without pretending to solve a runtime TOCTOU it structurally can't.

That said — happy to hear if the reviewers feel the conservative posture is warranted anyway. If so I can either (a) gate file:// resources behind an explicit allowlist of safe roots, or (b) drop file:// from the dialog entirely and leave it to hand-authored JSON. Just say which and I'll turn it around.

@RohanK6

RohanK6 commented Aug 9, 2026

Copy link
Copy Markdown
Contributor Author

Status: this PR is ready for review. I am currently working through the newest incoming merge conflicts in the shared i18n translation registry (en.context.json / locale catalogs) as other PRs land on main — these are rebase-only, no functional code changes, just keeping the branch mergeable and the translation keys in sync. The feature diff is unchanged from the reviewed state.

@RohanK6

RohanK6 commented Aug 9, 2026

Copy link
Copy Markdown
Contributor Author

The Frontend Tests failure here is a pre-existing upstream issue on main, not from this change.

The failing suite is src/i18n/catalogParity.test.ts on the ko catalog, namespace pages.sessionStorage.* — unrelated to this PR (whose keys are components.agentTemplateCreator.*). CI runs the PR branch merged with main, so it inherits main's state.

Evidence it's on main, not this PR:

  1. Pristine origin/main (no PR changes): en has 36 pages.sessionStorage.* keys, ko has 43 → 29 missing + 36 stray in ko — the session-storage feature landed with an out-of-sync Korean catalog.
  2. Unrelated open PR fix(sidebar): preserve relevance order in active-session search results #2299 fails identically: catalog parity > ko > missing 29 key(s), e.g. pages.sessionStorage.background_group.

These are the exact counts/keys this PR's CI reports. A re-run won't clear it; it needs a ko sessionStorage sync to land on main.

This PR's own suites are green — backend test_agent_template_create.py 106/106, i18n:check clean, and catalog parity passes for every locale except the upstream-broken ko.

iamwhatever
iamwhatever previously approved these changes Aug 9, 2026
@RohanK6

RohanK6 commented Aug 9, 2026

Copy link
Copy Markdown
Contributor Author

Updated screenshots. Rebased onto latest main (which now includes #1346's two-pane Agent Templates inspector), so I refreshed the whole walkthrough to show the create flow inside the new inspector — the Create template button now lives in the Templates roster header and the empty-state, and after-create still lands on the selected inspector view. No functional changes to the feature; these images are pinned to cab0d2c0a so they stay stable.

Entry point — Create template button in the Templates roster entry
Empty dialog — identity, model, prompt, skills, tools, MCP servers empty
Duplicate name refused client-side before any request duplicate
Complete draft — mapped skills, fs_read auto-approved (green shield), inline MCP server feeding an @release-notes mount suggestion, guardrails draft
After create — new template selected in the inspector with everything the form authored created

@bolichen97

Copy link
Copy Markdown
Collaborator

Overlap notice — three PRs implement Agent Template authoring from the dashboard:

Recommendation: consolidate on #2383 as the base — widest scope (create/edit/clone + all #2255 items), the only branch without merge conflicts, and it matches what issues #1829 and #2255 asked for. However, #2383 is not yet merge-ready: CI is failing (frontend i18n gates, backend test shard, coverage gate), it ships no tests, and only the en catalog. Before merge it should adopt:

@kyleseaman @RohanK6 — inviting you both to review #2383 so the best parts of all three land. If maintainers prefer the original sequencing (#2023 first, #2383 rebased back into the fast-follow it started as), that also works; the main thing is that the tests and i18n coverage from the other two PRs are not lost.

@kyleseaman

Copy link
Copy Markdown
Collaborator

Happy to close mine. I like this change.

The Agent Templates surface could inspect installed templates and edit
their model and skill mappings, but could not create one — a user who
needed a different capability set had to hand-edit ~/.kiro/agents/.

Backend: POST /api/agents/installed validates the complete template
(name charset doubling as the file stem, reserved/duplicate identity by
spec name across all specs, shape-validated tools/allowedTools/
mcpServers/resources/deniedCommands with an allowlist per MCP server
entry), maps catalog skill keys to skill:// resources through the
enumerated catalog (never by joining caller strings onto a path), and
writes ~/.kiro/agents/{name}.json atomically under the config lock. The
written stem equals the spec name, so discovery classifies it as
user-owned; framework and package ownership rules are untouched. Every
rejection names the offending field alongside the error-code contract.

Frontend: a Create template action on Agent Capabilities → Agent
Templates (plus an empty-state entry point) opens a structured
authoring dialog — identity, model, system prompt, skill catalog
toggles, tool chips with per-tool auto-approve, inline MCP server rows,
and advanced resources/guardrails. Nothing saves until Create; a server
rejection highlights the named field without discarding the draft. The
created template is selected in the inspector and appears in the Crew
template selector immediately.
@RohanK6

RohanK6 commented Aug 9, 2026

Copy link
Copy Markdown
Contributor Author

Sounds good, happy to go with #2383 — glad to help port the tests, translations, and docs over, and to review. Just let me know.

I'll leave #2023 open for now in case people would rather follow the alternative merge sequence.

@RohanK6

RohanK6 commented Aug 11, 2026

Copy link
Copy Markdown
Contributor Author

Resolving in favor of #2383

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

fork Pull request from a fork (external contributor) merge conflict Branch has merge conflicts with its base — author must resolve before merge

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add dashboard authoring for custom Agent Templates

4 participants