Skip to content

docs(coding-agents): Kiro IDE application session tracing (TH-8286) - #927

Open
nik13 wants to merge 9 commits into
mainfrom
feat/th-8286-kiro-ide
Open

nik13 wants to merge 9 commits into
mainfrom
feat/th-8286-kiro-ide

Conversation

@nik13

@nik13 nik13 commented Oct 15, 2026 •

Copy link
Copy Markdown
Contributor

Summary

Kiro IDE agent session tracing (TH-8286), on the shared hook-to-OTLP emitter from #912.

  • Adapter examples/coding-agents/hook-to-otlp/adapters/kiro_ide.py + contract tests + hook-config tests + fixture (tests/fixtures/kiro_ide/session.jsonl)
  • Install assets examples/coding-agents/kiro-ide/ (.kiro/hooks/fi-hook-to-otlp.json project and global templates, install.sh, run_e2e.sh)
  • Page src/pages/docs/integrations/coding-agents/kiro-ide.mdx, nav entry after // coding-agents:kiro-ide
  • Kiro docs used (read 2026-10-14): Hooks, Hook types, Hook actions, Configuration scopes

Span tree: Kiro IDE session -> Kiro IDE turn (UserPromptSubmit..Stop) -> completed tool spans (PostToolUse; ERROR when tool_response.success is false), Spec task (PostTaskExec), File created/saved/deleted. Observe-only: the gating triggers PreToolUse and PreTaskExec are not registered, so tool and spec-task spans have no duration. The adapter prints nothing on stdout (Kiro adds hook stdout to the agent context).

Every shipped command is the canonical guarded subshell, with the trigger on argv:

(python3 -B .kiro/fi-hook-to-otlp/emit.py kiro_ide PostToolUse 2>/dev/null || true)                 # project
(python3 -B "$HOME/.kiro/fi-hook-to-otlp/emit.py" kiro_ide PostToolUse 2>/dev/null || true)          # --user

Exit 0 and no output when the emitter or python3 is missing (Kiro blocks a prompt on exit 2 and keeps the agent working on a Stop exit 1), and the payload reaches python3 on stdin or as a trailing heredoc.

Checked against the real Kiro IDE 1.2.37 (macOS arm64, installed under the workspace, not /Applications)

  • Payload contract: the shipped kiro.kiro-agent extension builds {session_id, hook_event_name, cwd} plus prompt / tool_name / tool_input / tool_response / spec_name / task_name / task_success / file_path / reason per trigger; the fixture follows that builder.
  • Trigger names: the extension's enum is SessionStart, SessionEnd, Stop, PreToolUse, PostToolUse, PreTaskExec, PostTaskExec, UserPromptSubmit, PostFileCreate, PostFileSave, PostFileDelete, Manual.
  • Hook runner: spawn(command, {shell: true}) (/bin/sh -c on macOS/Linux, cmd.exe on Windows, which the page marks untested), cwd = the first workspace folder, payload on stdin. Exit-code handling read from the bundle: exit 2 on UserPromptSubmit/PreToolUse/PreTaskExec blocks, Stop exit 1 means "keep working", exit-0 stdout on SessionStart/UserPromptSubmit goes to the agent context.
  • Hook file: both templates pass a check against the extension's hook-file schema (version: "v1", hooks[] with name/trigger/matcher/action{type:command,command}/timeout).
  • PRD correction: the PRD treats SessionEnd as unavailable in the IDE. The 1.2.37 extension fires it, but on session runtime teardown (chat closed, window reloaded, app quit; the loader logs "loaded session runtime teardown"), and reloads the same session id later. So it is not mapped to a terminal session end: it closes a still-open turn (kiro.turn.ended_by=SessionEnd) and keeps the session state, and a reopened chat continues in the same trace at the next turn number.

How to run

cd examples/coding-agents/hook-to-otlp && python3 -m unittest discover -s tests -t .
FI_API_KEY=... FI_SECRET_KEY=... FI_BASE_URL=http://localhost:14338 FI_PROJECT_NAME=kiro-ide-e2e \
  HOOK_TRANSPORT=stdin examples/coding-agents/kiro-ide/run_e2e.sh   # or heredoc; unset = call emit.py directly

E2E evidence (local Future AGI)

Round 2 (2026-10-15, head of this PR): run_e2e.sh installed the recipe into a temp project with install.sh and ran the shipped hook-file commands through $SHELL -c, payload on stdin and as a heredoc. Every hook exit 0, empty stdout.

Project th8103-coding-kiro-ide, traces 85f34d04-3c45-79cb-2570-474f4a8e8dd6 (stdin) and e1a51bfe-940c-3d1c-de01-cfa21ad6569c (heredoc), both:

- [agent] Kiro IDE session (2391ms)
  - [chain] Kiro IDE turn (1988ms)
    - [tool] read_file (0ms)
    - [tool] execute_bash status=ERROR:tool reported failure (0ms)
    - [chain] File saved (0ms)
    - [chain] Spec task (0ms)
PASS

Unit tests: full suite 83 OK (core + Cursor + Kiro IDE, incl. 11 hook-config/installer tests across sh/zsh/bash/dash). Docs build and audit-links pass (0 broken nav/content links).

Privacy proof

  • Default (round 2): stored spans and the OTLP dump for both traces contain 0 prompt/tool/spec markers, 0 /Users/ paths, 0 occurrences of the local user name or host name. A test feeds a failed tool response with a path and user name and asserts it is absent by default (status message is the fixed "tool reported failure").
  • FI_HOOK_CAPTURE_CONTENT=1 (project th8103-coding-kiro-ide-content, trace c2c355ce-c5e6-3689-fcc9-567c5025e170, heredoc transport): prompt on the turn's input, tool input/output and the failed tool's response present.
  • cwd and the USER_PROMPT env var are never read or exported.

Verification (2026-10-20)

How others support Kiro: Langfuse (hooks; IDE, CLI) and Arize Phoenix (CLI hooks, page) trace Kiro via hooks; no page found for the other vendors. Same mechanism as this PR.

  • Real: a signed-in Kiro CLI 2.31.1 agent session (the CLI loads the same .kiro/hooks/*.json schema and payloads) ran this recipe's commands: project th8103-livefill-th8286 traces d703c81e-7824-12a4-dd9a-e960367542d3 (5 spans) and 2af17236-3ebc-574f-176e-5f2a4daa3a06 (7 spans, incl. File created/saved, fs_write); fi_verify PASS. Content opt-in project th8103-livefill-th8286-content trace fcc83d74-665f-419d-a673-81bce429a0f7, PASS.
  • Privacy scan (default): 0 hits for prompt/file markers, ENOENT text, /Users/, user and host name, input.value; opt-in: markers present, user name 0.
  • Finding fixed: real failed tools return a plain string (Caught error reading: ENOENT ...), not {success:false}; the adapter now marks it ERROR with the fixed message (new test; suite 84 OK).
  • Still a stand-in: the Kiro IDE app was not signed in or launched; IDE-only triggers (PostTaskExec, SessionEnd teardown, sh -c from the workspace folder) stay doc/extension-derived. Pushed 6291fa6; docs build + audit-links pass.

Limitations (on the page)

No model, tokens, cost, model-call spans, tool call ids or tool duration in this observe-only recipe; manual saves do not fire file hooks; Kiro Web/cloud sessions do not run hooks; enterprise daily OTel metrics are not used. Kiro CLI V3 also loads .kiro/hooks/ and ~/.kiro/hooks/, so CLI sessions in a project with this file (or anywhere after --user) are labelled Kiro IDE. The installer refuses when the Kiro CLI recipe's hook file (#928) is in the project or in ~/.kiro/hooks/, since both files would fire in every session, and warns when a Kiro CLI agent profile runs the Kiro CLI emitter (CLI sessions using that agent load this file too). Native Windows is not tested.

Review fixes

Round 1 (9f04e51, c575f98): PreToolUse/PreTaskExec dropped; SessionEnd no longer terminal; spec tasks completion-only; troubleshooting and "tested with" wording.

Round 2 (this push):

  • Subshell guard ( ... 2>/dev/null || true) with -B and the trigger on argv in both templates and the page (the project file also had a doubled || true || true).
  • tests/test_kiro_ide_hooks_config.py: every shipped command through sh/zsh/bash/dash, payload on stdin and as a heredoc; emitter missing, python3 missing, installed project and --user (run from another workspace); exit 0, empty stdout, payload verbatim, no __pycache__; regression showing the unparenthesized form loses a heredoc payload; installer refusal and stale-file cases.
  • SessionEnd also closes a still-open turn, so tools of an interrupted turn never point at a parent that is never exported; tests for reload (turn-2 under the same root), mid-turn SessionEnd, spec-task retry, error text privacy.
  • Installer: refuses when the Kiro CLI recipe shares a scope (both file names), refuses a foreign same-named file, says when an existing hook file is stale; uninstall documented.
  • Page: guard and exit-code behaviour explained, Windows caveat, matcher in the snippet, stale Pre/Post timing and user_decision text removed, SessionEnd and incomplete-turn rows match the code, CLI warning covers --user and both directions, softened env-file wording, Uninstall section.
  • Merged the foundation head 9b77d51 (emit.py prints nothing on failure paths).
  • Not changed: the absolute link to the Kiro CLI page stays absolute because that page only exists in docs(coding-agents): Kiro CLI application session tracing (TH-8287) #928; a relative link would fail audit-links in this branch.

Round 3 (e134c66): #928's install.sh --agent-profile now refuses when this recipe is in ~/.kiro/hooks (a session that uses an agent profile still loads every standalone hook file). For the reverse order, this installer now warns when a Kiro CLI agent profile in ~/.kiro/agents (or $KIRO_HOME/agents, nested, .json or .md) or the project's .kiro/agents runs the Kiro CLI emitter, and names the profile. It warns rather than refuses because it cannot know where the agent is used. New test (fails against the round-2 installer); the page's "Kiro CLI in the same project" warning says the same.

Optional follow-up (not a merge blocker)

Tracker status: DONE (replicated), since the real Kiro CLI 2.31.1 session above ran this recipe's hook file. Optional: sign in to Kiro IDE once and run one IDE chat with the installed hook file, to confirm one trace with session -> turn -> tool spans, prompt absent by default, and when SessionEnd fires (chat close vs app quit). The page already states the IDE app itself was not run.

🤖 Generated with Claude Code

nik13 and others added 5 commits October 14, 2026 20:54
Kiro IDE agent hooks -> shared hook-to-OTLP emitter. New kiro_ide adapter:
SessionStart/SessionEnd -> session, UserPromptSubmit/Stop -> turn (keyless),
Pre/PostToolUse -> FIFO-paired tool spans (ERROR when tool_response.success
is false), Pre/PostTaskExec -> spec task, PostFile* -> file events. Prints
nothing on stdout (Kiro adds hook stdout to the agent context).

Payload shapes follow kiro.dev/docs/hooks and the payload builder shipped in
Kiro IDE 1.2.37; hook templates match its v1 hook-file schema. Adds the
.kiro/hooks templates, install.sh, run_e2e.sh, the docs page and nav entry.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
…H-8286)

Remove gating hooks, preserve state across SessionEnd, guard shell commands, and add missing-emitter/resume coverage.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Use the global emitter path in the user template and keep the fail-open guard.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
…pen turn (TH-8286)

- Every shipped command (project and user hook file, page snippet) is the
  canonical subshell guard `(python3 -B <emit.py> kiro_ide <Trigger>
  2>/dev/null || true)` with the trigger on argv: exit 0 and no output when
  the emitter or python3 is missing, and the payload reaches python3 on
  stdin or as a trailing heredoc (the bare `|| true` form fed a heredoc to
  `true`; the project file also had a doubled `|| true || true`).
- tests/test_kiro_ide_hooks_config.py runs every shipped command through
  sh/zsh/bash/dash with the payload on stdin and as a heredoc: emitter
  missing, python3 missing, installed (project and --user from another
  workspace); asserts exit 0, empty stdout, payload received verbatim, no
  __pycache__, plus the unparenthesized-heredoc regression.
- SessionEnd (Kiro runtime unload, same session id reloaded later) now also
  closes a still-open turn (kiro.turn.ended_by=SessionEnd) so its tool spans
  never point at a parent that is never exported; session state and turn
  numbering are kept. Tests: reload continues at turn-2 under the same root,
  mid-turn SessionEnd, spec-task retry keeps both attempts, error text with
  a path and user name absent by default.
- install.sh refuses when the Kiro CLI recipe's hook file is in the project
  or ~/.kiro/hooks (both surfaces load both files), refuses a foreign
  same-named file, says when an existing hook file is stale, documents
  uninstall; env-file wording softened.
- Page: guard explained (exit 2 / Stop exit 1 / stdout to context), Windows
  cmd.exe caveat, matcher in the snippet, stale Pre/Post timing and
  user_decision text removed, SessionEnd and incomplete-turn rows match the
  code, CLI warning covers --user and both directions, Uninstall section.
- Fixture: dropped PreToolUse/PreTaskExec lines the recipe never registers;
  run_e2e.sh HOOK_TRANSPORT=stdin|heredoc runs the installed commands.
- Merged the foundation head 9b77d51 (emit.py prints nothing on failure).

Co-Authored-By: Claude Opus 5.5 <[email protected]>
nik13 and others added 2 commits October 15, 2026 13:19
…rofile (TH-8286)

Kiro CLI sessions that use an agent profile running the Kiro CLI recipe's
hooks (its --agent-profile setup) also load the Kiro IDE hook file, so they
would be exported twice. The installer cannot know where that agent is used,
so it warns and names the profile in ~/.kiro/agents (or $KIRO_HOME/agents) or
the project's .kiro/agents. This is the reverse order of the Kiro CLI
installer's new --agent-profile refusal. Test and page updated.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
…Kiro, live-agent verification (TH-8286)

Co-Authored-By: Claude Opus 5.5 <[email protected]>
@nik13
nik13 marked this pull request as ready for review October 21, 2026 22:18
Base automatically changed from feat/th-8229-cursor-hook-to-otlp to main October 29, 2026 05:37
nik13 and others added 2 commits October 29, 2026 03:42
Resolve src/lib/navigation.ts by keeping main's catalog-driven
Integrations sidebar; the page is listed through src/lib/integrations.mjs.

Co-Authored-By: Claude Opus 5.5 <[email protected]>

This branch has not been deployed

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant