feat(mcp): add list_recent_decisions tool (#1982)#111
Merged
saurabhjain1592 merged 1 commit intomainfrom May 8, 2026
Merged
Conversation
Member
Author
🚫 Release-window holdPer This PR depends on the platform-side endpoint + MCP tool registration in Runtime testing + verification on this branch only — do not merge to main. |
46e2d55 to
3765f98
Compare
saurabhjain1592
added a commit
to getaxonflow/axonflow-claude-plugin
that referenced
this pull request
May 7, 2026
Surfaces the V1.1 platform endpoint GET /api/v1/decisions in Claude Code
via the corresponding MCP tool exposed by the agent's MCP server. Adds
the slash command + skill + runtime-e2e gate so a Claude Code user can
ask "what just got blocked?" and get a structured tier-aware response.
Files:
- commands/axonflow-list-recent-decisions.md — new slash command.
- skills/list-recent-decisions/SKILL.md — new skill describing the
tool's args, response shape, and the tier cap-hit envelope handling.
Explicitly instructs the LLM to render the upgrade wording verbatim
on cap-hit instead of silently retrying or summarizing.
- runtime-e2e/list-recent-decisions/{README.md,test.sh,EVIDENCE.txt} —
wire-level proof: MCP server advertises the tool, happy-path
tools/call returns the decisions shape, cap-hit returns the wrapped
V1 upgrade envelope with upgrade.compare_url + upgrade.buy_url +
limit_type=decision_list_size intact.
- tests/e2e/runtime-mcp-tools.sh — added 7th scenario for the
over-cap envelope. Locks in
feedback_429_no_upgrade_hint_is_conversion_gap.md at the wire level
so a future regression that swallows the cap-hit fails CI.
- CHANGELOG.md — Unreleased "Added" section.
DO NOT MERGE — V1.1 release window is gated by user authorization
per feedback_v1_1_no_merge_during_release_window.md. The platform
side (axonflow-enterprise#1985) and the openclaw plugin side
(getaxonflow/axonflow-openclaw-plugin#111) are also held open;
all three land together when V1.1 ships.
Signed-off-by: Saurabh Jain <saurabhjain1592@gmail.com>
3765f98 to
600aacb
Compare
saurabhjain1592
added a commit
to getaxonflow/axonflow-claude-plugin
that referenced
this pull request
May 8, 2026
Surfaces the V1.1 platform endpoint GET /api/v1/decisions in Claude Code
via the corresponding MCP tool exposed by the agent's MCP server. Adds
the slash command + skill + runtime-e2e gate so a Claude Code user can
ask "what just got blocked?" and get a structured tier-aware response.
Files:
- commands/axonflow-list-recent-decisions.md — new slash command.
- skills/list-recent-decisions/SKILL.md — new skill describing the
tool's args, response shape, and the tier cap-hit envelope handling.
Explicitly instructs the LLM to render the upgrade wording verbatim
on cap-hit instead of silently retrying or summarizing.
- runtime-e2e/list-recent-decisions/{README.md,test.sh,EVIDENCE.txt} —
wire-level proof: MCP server advertises the tool, happy-path
tools/call returns the decisions shape, cap-hit returns the wrapped
V1 upgrade envelope with upgrade.compare_url + upgrade.buy_url +
limit_type=decision_list_size intact.
- tests/e2e/runtime-mcp-tools.sh — added 7th scenario for the
over-cap envelope. Locks in
feedback_429_no_upgrade_hint_is_conversion_gap.md at the wire level
so a future regression that swallows the cap-hit fails CI.
- CHANGELOG.md — Unreleased "Added" section.
DO NOT MERGE — V1.1 release window is gated by user authorization
per feedback_v1_1_no_merge_during_release_window.md. The platform
side (axonflow-enterprise#1985) and the openclaw plugin side
(getaxonflow/axonflow-openclaw-plugin#111) are also held open;
all three land together when V1.1 ships.
Signed-off-by: Saurabh Jain <saurabhjain1592@gmail.com>
Wraps the V1.1 platform endpoint GET /api/v1/decisions as an
OpenClaw-callable agent tool: surfaces the caller's recent governance
decisions for "what just got blocked" UX, appeal/override flows, and
forensic decision-history tracing.
Tool: axonflow_list_recent_decisions
- Inputs: since (RFC3339), decision (allow|deny|require_approval),
policy_id, tool_signature, limit (1-1000).
- Output: { decisions: [...] } on happy path, OR
{ upgrade_required: true, envelope: {...} } when a Free user
hits the tier page cap.
The 429 envelope passthrough is the critical Pro-conversion surface
per feedback_429_no_upgrade_hint_is_conversion_gap.md. The new
AxonFlowClient.listRecentDecisionsStrict method delegates to the
existing handleEnvelope helper so the throttle file is stamped + the
upgrade wording is logged once-per-day, AND the structured envelope
is returned to the agent-tool wrapper so the host LLM/UI can render
the buy_url + compare_url. decision_list_size added to V1_LIMIT_TYPES
so handleEnvelope recognizes the new limit type.
Pre-existing bugs caught + fixed in same PR (Rule 2):
- runtime-e2e/_lib/openclaw-runtime.sh was checking for "Registered 5
agent-callable tools" — stale since V1 Plugin Pro added 5 more
(real count: 11 with this PR). Replaced with a regex that doesn't
go stale on tool additions.
- tests/e2e/runtime-tools-smoke.mjs's expectedNames was frozen at 5
for the same reason — extended to the full 11-tool surface.
Tests:
- agent-tools.test.ts: 4 new cases (forwarding, decision-enum
validation, V1 envelope passthrough, transport error).
- registration.test.ts: count assertion 10 → 11 + new tool name.
- upgrade-prompt.test.ts: V1_LIMIT_TYPES locked enumeration extended.
- runtime-e2e/list-recent-decisions/test.sh: wire-level proof that
the MCP server advertises the tool, happy-path tools/call returns
the decisions shape, AND cap-hit returns the wrapped V1 envelope
with buy_url + compare_url + limit_type=decision_list_size intact.
All 450 unit tests pass; runtime-e2e PASSES live against
docker-compose at localhost:8080.
DO NOT MERGE — V1.1 release window is gated by user authorization
per feedback_v1_1_no_merge_during_release_window.md.
Signed-off-by: Saurabh Jain <saurabhjain1592@gmail.com>
600aacb to
513f8c5
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
V1.1 (axonflow-enterprise#1982) — adds
axonflow_list_recent_decisionsto OpenClaw's agent-callable tool surface. Companion to the existingaxonflow_explain_decisiontool:explainanswers "why was this blocked?" for a single decision;list_recent_decisionsanswers "what's been blocked recently?" with a 5-field summary per row.What changed
src/upgrade-prompt.tsdecision_list_sizetoV1_LIMIT_TYPES. Required forhandleEnvelopeto recognize the new V1.1 limit type — without this, the throttle gate would silently drop the upgrade wording.src/axonflow-client.tslistRecentDecisionsStrictmethod. Returns{ kind: "ok", decisions }on 200 /{ kind: "envelope", envelope }on 429 / throws on other non-2xx. The 429 path runs through the existinghandleEnvelopehelper so the throttle file is stamped + the upgrade wording is logged once-per-day.src/agent-tools.tsbuildListRecentDecisionsTool. Maps the JSON-Schema args → client method. On envelope hit, returns a structured tool result withupgrade_required: trueso the host LLM/UI can render the upgrade prompt.src/index.tsbuildListRecentDecisionsTool.agent-tools.test.tscases (forwarding, decision-enum, envelope passthrough, transport error). Updated registration count 10→11. UpdatedV1_LIMIT_TYPESlock test.runtime-e2e/list-recent-decisions/tools/listadvertisement check + happy-path + cap-hit envelope passthrough.tests/e2e/runtime-tools-smoke.mjsexpectedNameswas stale at 5 (V1 Pro added 5 more, never updated) — extended to the full 11-tool surface.runtime-e2e/_lib/openclaw-runtime.shRegistered 5 agent-callable toolsregex was stale since V1 Plugin Pro. Replaced withRegistered [0-9]+so the gate doesn't break on every tool addition.Three-rule definition of done
Rule 0 — Runtime proof
Captured at
runtime-e2e/list-recent-decisions/EVIDENCE.txt:Also verified via
tests/e2e/runtime-tools-smoke.mjsagainst the live stack:Rule 1 — Self-review
Hunk-by-hunk per the 5-question protocol from
feedback_self_review_is_mandatory_every_pr.md:execute()does NOT collapse 429 intoisError: true. Thekind === "envelope"branch returns the upgrade message + structureddetailsso the host renders it as success-with-upgrade-prompt, not as a tool failure. This is the exact gap fromfeedback_429_no_upgrade_hint_is_conversion_gap.md.decision_list_sizewas added toV1_LIMIT_TYPES. Without this,handleEnvelopewould short-circuit at line 309-314 (if (!V1_LIMIT_TYPES.includes(envelope.limit_type))) and silently drop the wording.decisionenum check before the HTTP call) so a malformed arg becomes a structuredisErrorinstead of a wasted round-trip.listRecentDecisionsStrictdistinguishes 429 (envelope) from other non-2xx (throwsAxonFlowHttpError) — same defense-in-depth shape as the existingsearchAuditEventsStrict/listOverridesStrictmethods.Rule 2 — No deferred bugs
Two stale checks fixed in this same PR rather than handed off to "another session":
runtime-tools-smoke.mjsexpectedNames(was frozen at 5; bumped to 11).openclaw-runtime.shRegistered 5regex (replaced withRegistered [0-9]+).Both were latent since the V1 Plugin Pro tools landed; the broken state was simply masked because nobody ran the e2e since then.
Test plan
npx jest --no-coverage— 450/450 passnpx tsc --noEmit— cleanbash runtime-e2e/list-recent-decisions/test.shagainst docker-compose at localhost:8080 — PASSnode tests/e2e/runtime-tools-smoke.mjsagainst docker-compose at localhost:8080 — PASSDo NOT merge
Per
feedback_v1_1_no_merge_during_release_window.md: V1.1 release-window PRs stay open until user explicitly authorizes the V1.1 release. This PR consumes the platform endpoint atgetaxonflow/axonflow-enterprise#1985(also held open). Both land together when V1.1 ships.