Skip to content

feat: AgentCard OAuth integration + agent skill#4035

Draft
keyserfaty wants to merge 6 commits into
Kilo-Org:mainfrom
keyserfaty:feat/agentcard-kilo-integration
Draft

feat: AgentCard OAuth integration + agent skill#4035
keyserfaty wants to merge 6 commits into
Kilo-Org:mainfrom
keyserfaty:feat/agentcard-kilo-integration

Conversation

@keyserfaty

Copy link
Copy Markdown

Adds a first-class AgentCard integration to KiloClaw: a "Connect Agentcard" OAuth 2.1 (PKCE) flow replacing the paste-a-token approach, automatic per-instance MCP server configuration, and an agent skill so a connected user can just say "create a card."

What's included

OAuth integration (apps/web)

  • integrations/agentcard: connect / callback / disconnect routes, agentcard-service, signed PKCE OAuth state, and an encrypted per-user connection store (kiloclaw_agentcard_oauth_connections, migration 0159).
  • Token-refresh cron (/api/cron/agentcard-token-refresh, every 10m) that re-pushes the refreshed access token to the instance.
  • Settings "Agentcard" card + post-connect prompt; kiloclaw-router exposes connection status. AGENTCARD_API_KEY added to the kiloclaw secret catalog.

MCP wiring + discoverability (services/kiloclaw)

  • Controller restore regenerates the mcporter config so the agentcard MCP server appears as soon as the token is present.
  • New skills/agentcard/SKILL.md (baked into the image) + a gated TOOLS.md section so the agent reliably reaches for AgentCard on "create a card" — no manual MCP install.

Notes

  • Draft pending coordination with the Kilo team.
  • Local-only dev tweaks (R2 remote:false, docker-compose port remaps, a local LLM shim) were intentionally kept out of this branch.
  • One follow-up: the agentcard mcporter entry stores a literal token vs a ${VAR} template — fine across restores, but worth aligning later.

🤖 Generated with Claude Code

keyserfaty and others added 6 commits June 15, 2026 23:01
Ship an AgentCard skill and the tools.md discoverability hint, baked into
the KiloClaw image, so a connected user can just say "create a card" and the
agent uses the agentcard MCP server correctly — with no manual MCP install.

- skills/agentcard/SKILL.md: how to call agentcard via mcporter (introspect
  with `mcporter list agentcard`/--schema), common tools (create_card needs
  amount_cents), test-mode note, and a "connect in Settings -> Payments"
  fallback. Baked in by the existing `COPY skills/ /root/clawd/skills/` and
  auto-discovered (mirrors the weather skill).
- bootstrap.ts: AGENTCARD_SECTION_CONFIG + updateToolsMdSection gated on
  AGENTCARD_API_KEY, mirroring the Linear pattern — the in-prompt trigger
  appears in TOOLS.md only once the user has connected.
- bootstrap.test.ts: marker-correctness + enable/disable coverage.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Replace the paste-a-token AgentCard flow with a "Connect AgentCard" OAuth
2.1 (PKCE) integration, and auto-configure the agentcard MCP server for the
user's KiloClaw instance.

- apps/web integrations/agentcard: connect/callback/disconnect routes,
  agentcard-service, signed OAuth state (PKCE), and the per-user OAuth
  connection store (encrypted access/refresh tokens).
- Token refresh cron (/api/cron/agentcard-token-refresh, every 10m) that
  re-pushes the refreshed access token to the instance.
- SettingsTab "Agentcard" card + AgentCardConnectPrompt post-connect screen;
  kiloclaw-router exposes connection status fields.
- DB migration 0159 + schema for kiloclaw_agentcard_oauth_connections;
  AGENTCARD_API_KEY added to the kiloclaw secret catalog.
- Controller restore regenerates mcporter config so the agentcard MCP server
  appears as soon as the token is present.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Addresses correctness issues found in a second-pass review of the
AgentCard OAuth integration:

- Refresh-token rotation race: AgentCard rotates refresh tokens (each
  refresh invalidates the previous one), so two overlapping cron sweeps
  could refresh the same connection and flip it to action_required.
  Add an atomic optimistic row claim (claimAgentCardConnectionForRefresh)
  so exactly one sweep processes each connection.
- Initial secret-push failure no longer silently reports success: the
  callback retries the worker push, and on final failure marks the
  connection action_required and redirects with an error instead of
  success (the cron only refreshes near-expiry tokens, so it would not
  re-push a fresh ~1h token for ~40 min).
- FK now ON DELETE CASCADE (matches sibling instance-scoped tables) so
  deleting a kiloclaw_instance can't fail on a lingering connection row.
  Amended migration 0159 + snapshot in place (table not yet shipped).
- Disconnect removes the worker secret BEFORE deleting the DB row so a
  push failure can't orphan a live token with no row to retry from, and
  now revokes the access token in addition to the refresh token.
- Remove dead getValidAgentCardAccessToken (+ unused imports/const).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The Stytch fraud-validation auto-pass and the KILOCLAW_DEV_MOCK fake
local-instance provisioning are local-dev-only conveniences (gated on
allow_fake_login) that don't belong in the AgentCard integration. Pulled
out to a separate branch (chore/local-dev-kiloclaw-mock) so this PR is
AgentCard-only and the dev/auth-bypass code gets reviewed on its own.

No behavior change to the AgentCard integration.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Expand the agentcard SKILL.md from the 6 card tools to the complete MCP
surface — cards, approvals, account/onboarding, plan & billing, payment
methods, connections, support, and the (extension-gated) browser checkout
tools — grouped with one-line usage. Notes that the checkout tools need
the Chrome extension and won't work in the headless agent.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…moval

Disconnect previously removed the worker secret first and fail-closed, so
if the KiloClaw worker was unreachable the whole disconnect aborted
(error=disconnect_failed) and nothing was revoked or cleared.

Reorder to make disconnect robust and actually revoke access:
1. Revoke the OAuth grant at AgentCard (refresh + access token) — the
   authoritative cut-off; invalidates the copy already on the worker too.
2. Clear the stored connection so the refresh cron stops touching it.
3. Remove the worker secret best-effort (failure no longer aborts the
   disconnect — the grant is already revoked, so only an already-dead
   token could remain).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
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