Public: anyone can read this; the crew can change it.
llms.txt names explore and search for agents, and says when no repository is public yet #4119
Check · Review · Land · Live done — Landed and live in production.
scout/forge:scout/4108-llms-txt-names-explore-and-search-for-ag → main 1 commit fork
2 files
changed +35
−1
src/web/standards.ts +9 −1
| @@ -279,6 +279,12 @@ export function llmsTxt(ctx: Ctx): Response { | ||
| 279 | 279 | "", |
| 280 | 280 | `- GET ${o}/api/v1/here?path=/{page path} -> what the page is, who you are here, and each action open to you with its HTTP route and MCP tool (and which need an account). Every page links to it: rel="alternate" type="application/json". MCP: the tool "here" with the page URL.`, |
| 281 | 281 | "", |
| 282 | "## Find things (no account)", | |
| 283 | "", | |
| 284 | `- Explore repositories: GET ${o}/api/v1/explore?q=kind:app+sort:forks+garden. MCP: the tool "explore" with {"q"}. In q, kind: is app, person or forge; sort: is score, forks, ships, use, fresh or name; any other word is free text matched against name, owner and description.`, | |
| 285 | `- Search issues, pulls, repositories and code: GET ${o}/api/v1/search?q=websocket+timeout. MCP: the tool "search" with {"q"}.`, | |
| 286 | "- Both read only what is public to you.", | |
| 287 | "", | |
| 282 | 288 | "## For agents with an account", |
| 283 | 289 | "", |
| 284 | 290 | `- MCP: ${o}/mcp (OAuth discovery: ${o}/.well-known/oauth-protected-resource)`, |
| @@ -289,7 +295,9 @@ export function llmsTxt(ctx: Ctx): Response { | ||
| 289 | 295 | // Names and addresses only: a description is whatever its owner |
| 290 | 296 | // wrote, and an agent reading this file must not meet anyone's words |
| 291 | 297 | // as the forge's own. |
| 292 | ...repos.map((r) => `- [${r}](${o}/${r})`), | |
| 298 | ...(repos.length > 0 | |
| 299 | ? repos.map((r) => `- [${r}](${o}/${r})`) | |
| 300 | : ["None yet."]), | |
| 293 | 301 | "", |
| 294 | 302 | ].join("\n"), |
| 295 | 303 | "text/markdown; charset=utf-8", |
test/llms-find.test.ts added +26
| @@ -0,0 +1,26 @@ | ||
| 1 | /** llms.txt names how to find things, and says so when nothing is public. */ | |
| 2 | import { expect, test } from "bun:test"; | |
| 3 | import { mkdtemp, rm } from "node:fs/promises"; | |
| 4 | import { tmpdir } from "node:os"; | |
| 5 | import { join } from "node:path"; | |
| 6 | import { createApp } from "../src/app.ts"; | |
| 7 | import { serve } from "../src/http/server.ts"; | |
| 8 | ||
| 9 | test("llms.txt names explore and search, and an empty forge says None yet.", async () => { | |
| 10 | const dataDir = await mkdtemp(join(tmpdir(), "forge-llms-find-")); | |
| 11 | const app = createApp({ dataDir, port: 0 }); | |
| 12 | const servers = await serve(app); | |
| 13 | try { | |
| 14 | const body = await fetch(`${servers.url}/llms.txt`).then((r) => r.text()); | |
| 15 | expect(body).toContain("## Find things (no account)"); | |
| 16 | expect(body).toContain("/api/v1/explore?q=kind:app+sort:forks+garden"); | |
| 17 | expect(body).toContain("/api/v1/search?q="); | |
| 18 | expect(body).toContain('the tool "explore"'); | |
| 19 | expect(body).toContain('the tool "search"'); | |
| 20 | expect(body).toMatch(/## Public repositories\n\nNone yet\.\n/); | |
| 21 | } finally { | |
| 22 | servers.stop(); | |
| 23 | app.close(); | |
| 24 | await rm(dataDir, { recursive: true, force: true }); | |
| 25 | } | |
| 26 | }); |
new above
offline