AGENTS: publish /llms.txt, a calternal SKILL.md (+ /.well-known/agent-skills) and an MCP Server Card, generated from the action registry #630

Open
opened 2026-10-01 12:04:30 +00:00 by kayg · 7 comments
Owner

Owner request (2026-10-01): "Is there no convention to expose a skill at a subpath for agents that is a standard? Basically how to use the MCP, CLI, API, WebMCP, etc."

After the Aside fix, Aside lists 290 tools at https://calternal.cloud/mcp. Agents now also need a short, readable "how to use calternal" guide.
Conventions (research 2026-10-01; cite them in DESIGN):

  • /llms.txt (llmstxt.org, Answer.AI): a Markdown index at the site root that agents fetch routinely (Claude Code, Cursor, Copilot…).
  • Agent Skills (SKILL.md): the skill package format (Anthropic Skills; open agent platforms). There is an emerging proposal to list skills under a ## Skills section in llms.txt, with /.well-known/agent-skills/index.json as the metadata/integrity layer (draft, not yet a standard).
  • MCP Server Cards (SEP-2127): /.well-known/mcp-server-card (or /.well-known/mcp/server-card.json) describes the MCP endpoint, transports, protocol versions and auth before connecting.
  • OpenAPI at a stable path for the HTTP API (/api/openapi.json or similar); WebMCP tools are registered in-page (navigator.modelContext).
    Build (generated from the #484 action registry; one source; no hand-written duplication):
  1. GET /llms.txt (public, no auth, no User data): what calternal is; how to connect via MCP (URL, Authorization: Bearer <App Password>, the App Password preset to choose), CLI (calternal --server …, auth), HTTP API (the OpenAPI link, auth), WebMCP (available when the web app is open); the Skills section; links to the docs below.
  2. GET /skills/calternal/SKILL.md (+ /.well-known/agent-skills/index.json with name, description, URL, sha256): a concise skill: when to use which surface, auth setup, the main tool groups (calendar/journal, tasks, notes, files, photos, mail, money), conventions (IDs, deep links §33, dates/time zones, undo), safety (writes are logged and undoable), and examples. Generated at build time from the registry + a short hand-written intro.
  3. GET /.well-known/mcp-server-card (SEP-2127 shape): name, version, endpoint /mcp, the supported protocol versions (2025-03-26 … 2026-07-28), transport, auth (bearer App Password), and the docs link.
  4. Link them from Settings → Apps (the AI assistant setup, #629).
    All public, cacheable, with no per-User data, and they reflect admin-disabled surfaces (if MCP is off, the card says so).
    Tests: contract tests that each path returns the right content type and links resolve; the SKILL.md tool groups match the registry; a test that the server card protocol list equals MCP_PROTOCOLS.
## Owner request (2026-10-01): "Is there no convention to expose a skill at a subpath for agents that is a standard? Basically how to use the MCP, CLI, API, WebMCP, etc." After the Aside fix, Aside lists **290 tools** at `https://calternal.cloud/mcp`. Agents now also need a short, readable "how to use calternal" guide. **Conventions (research 2026-10-01; cite them in DESIGN):** - **`/llms.txt`** (llmstxt.org, Answer.AI): a Markdown index at the site root that agents fetch routinely (Claude Code, Cursor, Copilot…). - **Agent Skills (`SKILL.md`)**: the skill package format (Anthropic Skills; open agent platforms). There is an emerging proposal to list skills under a `## Skills` section in llms.txt, with `/.well-known/agent-skills/index.json` as the metadata/integrity layer (draft, not yet a standard). - **MCP Server Cards (SEP-2127)**: `/.well-known/mcp-server-card` (or `/.well-known/mcp/server-card.json`) describes the MCP endpoint, transports, protocol versions and auth before connecting. - OpenAPI at a stable path for the HTTP API (`/api/openapi.json` or similar); WebMCP tools are registered in-page (`navigator.modelContext`). **Build (generated from the #484 action registry; one source; no hand-written duplication):** 1. `GET /llms.txt` (public, no auth, no User data): what calternal is; how to connect via **MCP** (URL, `Authorization: Bearer <App Password>`, the App Password preset to choose), **CLI** (`calternal --server …`, auth), **HTTP API** (the OpenAPI link, auth), **WebMCP** (available when the web app is open); the Skills section; links to the docs below. 2. `GET /skills/calternal/SKILL.md` (+ `/.well-known/agent-skills/index.json` with name, description, URL, sha256): a concise skill: when to use which surface, auth setup, the main tool groups (calendar/journal, tasks, notes, files, photos, mail, money), conventions (IDs, deep links §33, dates/time zones, undo), safety (writes are logged and undoable), and examples. Generated at build time from the registry + a short hand-written intro. 3. `GET /.well-known/mcp-server-card` (SEP-2127 shape): name, version, endpoint `/mcp`, the supported protocol versions (2025-03-26 … 2026-07-28), transport, auth (bearer App Password), and the docs link. 4. Link them from Settings → Apps (the AI assistant setup, #629). All public, cacheable, with no per-User data, and they reflect admin-disabled surfaces (if MCP is off, the card says so). **Tests:** contract tests that each path returns the right content type and links resolve; the SKILL.md tool groups match the registry; a test that the server card protocol list equals `MCP_PROTOCOLS`.
Author
Owner

Starting #630 on branch job/agentdocs-630, based on origin/dev at 3f258302a0. I am locating the #484 action registry, public route wiring, and Settings → Apps implementation before adding generated agent documentation and contract coverage.

Starting #630 on branch job/agentdocs-630, based on origin/dev at 3f258302a0f2d6418ff60c9ce22cbb33e008ca99. I am locating the #484 action registry, public route wiring, and Settings → Apps implementation before adding generated agent documentation and contract coverage.
Author
Owner

Finding: contracts/actions.json currently has 333 operations, and Settings → Apps stores User and Instance surface flags separately (wire.rs::read_app_surface_flags). Public docs will inspect only the Instance MCP flag and will not publish User state. Current primary sources identify MCP Server Cards as experimental and WebMCP as a Community Group draft; DESIGN citations will retain that status.

Finding: contracts/actions.json currently has 333 operations, and Settings → Apps stores User and Instance surface flags separately (wire.rs::read_app_surface_flags). Public docs will inspect only the Instance MCP flag and will not publish User state. Current primary sources identify MCP Server Cards as experimental and WebMCP as a Community Group draft; DESIGN citations will retain that status.
Author
Owner

Backend discovery slice committed: 4dfba5308eabdebd219e7d49661d6ff6c8efaafd.

Finding: the shared session middleware treated a global Bearer token as a credential for public docs. The five exact discovery paths now bypass session/token checks and strip Cookie and Authorization before the handler. The handler reads only Instance switches, so public cache responses contain no User-level flags or data.

Evidence: focused public-document contract tests pass (5/5); exact auth-bypass path test passes; cargo clippy -p calternal-server --all-targets -- -D warnings completed without diagnostics. The real-server adversarial round is still pending.

Backend discovery slice committed: `4dfba5308eabdebd219e7d49661d6ff6c8efaafd`. Finding: the shared session middleware treated a global Bearer token as a credential for public docs. The five exact discovery paths now bypass session/token checks and strip Cookie and Authorization before the handler. The handler reads only Instance switches, so public cache responses contain no User-level flags or data. Evidence: focused public-document contract tests pass (5/5); exact auth-bypass path test passes; `cargo clippy -p calternal-server --all-targets -- -D warnings` completed without diagnostics. The real-server adversarial round is still pending.
Author
Owner

Post-merge adversarial finding: the combined MCP run stops at tests/adversarial/mcp_probe.py:471 before reaching the new document probes. The owner-role fixture receives calternal_api_admin_delete_user from tools/list, while the existing expected set deliberately excludes registry actions with the admin scope. I left that expectation and fixture unchanged, as required. I added a focused #630 probe mode so the public-document attack and benchmark can run independently; I will report their results separately.

Post-merge adversarial finding: the combined MCP run stops at `tests/adversarial/mcp_probe.py:471` before reaching the new document probes. The owner-role fixture receives `calternal_api_admin_delete_user` from `tools/list`, while the existing expected set deliberately excludes registry actions with the `admin` scope. I left that expectation and fixture unchanged, as required. I added a focused #630 probe mode so the public-document attack and benchmark can run independently; I will report their results separately.
Author
Owner

Visual and deep-link verification found two Settings issues. First, /settings/apps/agent-setup was normalized to /settings/apps because its group slug was missing from Settings section metadata; I registered it and added the route guard. Second, the phone-sheet title observer selected the CSS-hidden App Passwords heading, because it still queried the element with a zero-size box; the observer now skips zero-size headings, and the production screenshot probe checks the phone title. The deep-link and phone capture now pass on the production build.

Visual and deep-link verification found two Settings issues. First, `/settings/apps/agent-setup` was normalized to `/settings/apps` because its group slug was missing from Settings section metadata; I registered it and added the route guard. Second, the phone-sheet title observer selected the CSS-hidden App Passwords heading, because it still queried the element with a zero-size box; the observer now skips zero-size headings, and the production screenshot probe checks the phone title. The deep-link and phone capture now pass on the production build.
Author
Owner

Follow-up to the phone title fix: the first full web run showed that a zero-size DOM check depends on browser layout and makes jsdom headings look hidden. I replaced that check with the explicit data-sheet-title-ignore marker on Settings headings that are intentionally hidden on sheets. The focused OverlaySurface suite now passes 11/11, with the original title-ownership assertions unchanged.

Follow-up to the phone title fix: the first full web run showed that a zero-size DOM check depends on browser layout and makes jsdom headings look hidden. I replaced that check with the explicit `data-sheet-title-ignore` marker on Settings headings that are intentionally hidden on sheets. The focused `OverlaySurface` suite now passes 11/11, with the original title-ownership assertions unchanged.
Author
Owner

Implemented Forgejo #630 and committed the work.

Built

  • Public, cacheable /llms.txt, /skills/calternal/SKILL.md, /.well-known/agent-skills/index.json, /.well-known/mcp-server-card, and /api/openapi.json routes.
  • Build-generated Agent Skill based on the #484 action registry, with a shared tool-group classifier, exact-byte SHA-256 metadata, instance-level surface availability, and contract tests.
  • Settings → Apps links and the stable /settings/apps/agent-setup route. Fixed compact phone-sheet title selection for headings hidden from the sheet.
  • Public-document abuse probes and focused mode; local performance profile.

Files

  • Server: crates/calternal-server/build.rs, Cargo.toml, src/agent_docs.rs, src/agent_docs/groups.rs, src/agent_docs/skill_intro.md, src/mcp.rs, src/wire.rs; Cargo.lock.
  • Web and shared UI: apps/web/src/routes/settings/apps/AppsSection.svelte, apps/web/src/routes/settings/parts/SettingsCard.svelte, apps/web/src/routes/settings/sections.ts, sections.test.ts, shared-components.guard.test.ts, apps/web/src/lib/components/OverlaySurface.svelte.test.ts, packages/ui/src/components/OverlaySurface.svelte, Pill.svelte.
  • Docs and evidence: docs/DESIGN.md, docs/mcp.md, docs/perf/runs/2026-10-01-agent-docs-630.json, bench/agent-docs.py, tests/adversarial/mcp_probe.py, run.sh, setup.mjs.

Head

183ac356359f1f84afad30932f02e07323ddb7ed

Gates

Commands used the required cargo environment and per-crate scope. Output:

  • cargo fmt --check: exit 0, no output.
  • cargo clippy -p calternal-server --all-targets -- -D warnings:
    Finished \dev` profile [unoptimized + debuginfo] target(s) in 1m 13s`
  • cargo test -p calternal-server:
    test result: ok. 114 passed; 0 failed; 3 ignored; 0 measured; 0 filtered out; finished in 12.38s
  • bun run check: svelte-check found 0 errors and 0 warnings
  • bun run test:
    Test Files 148 passed (148)
    Tests 1012 passed (1012)
  • Production build: ✓ built in 1m 19s; Wrote site to "build".
  • Focused real-server probe: PASS public agent documents: anonymous and invalid-credential reads, hostile paths, oversized requests, and 48 parallel reads.

The broader MCP adversarial run stopped at its existing owner-role inventory assertion: the fixture exposed calternal_api_admin_delete_user in tools/list, while the unchanged expectation excludes registry actions with admin scope. I did not change that expectation. The focused #630 document probe passed.

Performance

Local debug-server profile; no comparable entry exists in docs/perf/baseline.json. For 50 samples per route, p50/p95 milliseconds were: llms 3.133/3.877; Skill 3.315/6.328; Skill index 3.685/4.959; Server Card 3.246/5.299; OpenAPI 4.029/5.449. The 32-client OpenAPI burst (631,582 bytes per response) measured 42.337/60.93 ms p50/p95, 0.16 CPU seconds, and 158,609,408-byte peak RSS. Load average before/after was 4.11/3.75/4.97.

Screenshots

Real production Settings page, six viewport/theme combinations:

Known gaps

The unrelated broader MCP inventory assertion above remains for follow-up; its expected behavior and fixture were left unchanged. The performance profile is local and has no prior baseline.

Decisions not specified in DESIGN

  • Added must-revalidate to the 60-second public cache policy.
  • Used CARGO_PKG_VERSION for the Server Card version.
  • Skill headless CLI guidance uses existing calternal login {base} plus CALTERNAL_TOKEN and CALTERNAL_TOKEN_SERVER.
Implemented Forgejo #630 and committed the work. ## Built - Public, cacheable `/llms.txt`, `/skills/calternal/SKILL.md`, `/.well-known/agent-skills/index.json`, `/.well-known/mcp-server-card`, and `/api/openapi.json` routes. - Build-generated Agent Skill based on the #484 action registry, with a shared tool-group classifier, exact-byte SHA-256 metadata, instance-level surface availability, and contract tests. - Settings → Apps links and the stable `/settings/apps/agent-setup` route. Fixed compact phone-sheet title selection for headings hidden from the sheet. - Public-document abuse probes and focused mode; local performance profile. ## Files - Server: `crates/calternal-server/build.rs`, `Cargo.toml`, `src/agent_docs.rs`, `src/agent_docs/groups.rs`, `src/agent_docs/skill_intro.md`, `src/mcp.rs`, `src/wire.rs`; `Cargo.lock`. - Web and shared UI: `apps/web/src/routes/settings/apps/AppsSection.svelte`, `apps/web/src/routes/settings/parts/SettingsCard.svelte`, `apps/web/src/routes/settings/sections.ts`, `sections.test.ts`, `shared-components.guard.test.ts`, `apps/web/src/lib/components/OverlaySurface.svelte.test.ts`, `packages/ui/src/components/OverlaySurface.svelte`, `Pill.svelte`. - Docs and evidence: `docs/DESIGN.md`, `docs/mcp.md`, `docs/perf/runs/2026-10-01-agent-docs-630.json`, `bench/agent-docs.py`, `tests/adversarial/mcp_probe.py`, `run.sh`, `setup.mjs`. ## Head `183ac356359f1f84afad30932f02e07323ddb7ed` ## Gates Commands used the required cargo environment and per-crate scope. Output: - `cargo fmt --check`: exit 0, no output. - `cargo clippy -p calternal-server --all-targets -- -D warnings`: `Finished \`dev\` profile [unoptimized + debuginfo] target(s) in 1m 13s` - `cargo test -p calternal-server`: `test result: ok. 114 passed; 0 failed; 3 ignored; 0 measured; 0 filtered out; finished in 12.38s` - `bun run check`: `svelte-check found 0 errors and 0 warnings` - `bun run test`: `Test Files 148 passed (148)` `Tests 1012 passed (1012)` - Production build: `✓ built in 1m 19s`; `Wrote site to "build"`. - Focused real-server probe: `PASS public agent documents: anonymous and invalid-credential reads, hostile paths, oversized requests, and 48 parallel reads`. The broader MCP adversarial run stopped at its existing owner-role inventory assertion: the fixture exposed `calternal_api_admin_delete_user` in `tools/list`, while the unchanged expectation excludes registry actions with admin scope. I did not change that expectation. The focused #630 document probe passed. ## Performance Local debug-server profile; no comparable entry exists in `docs/perf/baseline.json`. For 50 samples per route, p50/p95 milliseconds were: llms 3.133/3.877; Skill 3.315/6.328; Skill index 3.685/4.959; Server Card 3.246/5.299; OpenAPI 4.029/5.449. The 32-client OpenAPI burst (631,582 bytes per response) measured 42.337/60.93 ms p50/p95, 0.16 CPU seconds, and 158,609,408-byte peak RSS. Load average before/after was 4.11/3.75/4.97. ## Screenshots Real production Settings page, six viewport/theme combinations: - [390 light](https://git.kayg.org/attachments/e5483dcf-b147-474e-9fc2-3e65ce360291), [390 dark](https://git.kayg.org/attachments/99ae5e77-0867-4ce6-8f0f-e2ac67680bc5) - [820 light](https://git.kayg.org/attachments/093d19ad-cab4-4ea6-a44c-e109408c7fb6), [820 dark](https://git.kayg.org/attachments/066684cb-7f80-43c7-9609-54f5245e99c1) - [1440 light](https://git.kayg.org/attachments/bca8dbe3-1edb-49ec-9e50-80b8b5da6d53), [1440 dark](https://git.kayg.org/attachments/6e9b7a20-e2c7-409b-8d53-fca8eff73cf2) ## Known gaps The unrelated broader MCP inventory assertion above remains for follow-up; its expected behavior and fixture were left unchanged. The performance profile is local and has no prior baseline. ## Decisions not specified in DESIGN - Added `must-revalidate` to the 60-second public cache policy. - Used `CARGO_PKG_VERSION` for the Server Card version. - Skill headless CLI guidance uses existing `calternal login {base}` plus `CALTERNAL_TOKEN` and `CALTERNAL_TOKEN_SERVER`.
Sign in to join this conversation.
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
kayg/calternal#630
No description provided.