Skip to content

Commit d79b7e7

Browse files
authored
docs: ship agent guidance in TMA overlay (#28)
* docs: ship agent guidance in TMA overlay * feat(template): ship TMA knowledge skill and bootstrap token wiring
1 parent b94cebf commit d79b7e7

10 files changed

Lines changed: 405 additions & 1 deletion

File tree

README.md

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,11 +31,18 @@ npx --yes github:SpawnDock/create#main --token <pairing-token> [project-dir]
3131
- `spawndock.dev-tunnel.json`
3232
- `public/tonconnect-manifest.json`
3333

34+
`spawndock.config.json` may include `apiToken`, and `.env.local` may include
35+
`SPAWNDOCK_API_TOKEN`, so the bundled TMA knowledge-search skill can use the
36+
authenticated API tier immediately after bootstrap.
37+
3438
## Built-in Overlay
3539

3640
The package also ships a built-in TMA overlay and applies it after cloning
3741
`SpawnDock/tma-project`. This overlay is responsible for:
3842

43+
- `AGENTS.md`
44+
- `CLAUDE.md`
45+
- `.agents/skills/tma-knowledge-search`
3946
- `spawndock/dev.mjs`
4047
- `spawndock/next.mjs`
4148
- `spawndock/tunnel.mjs`
@@ -51,8 +58,12 @@ The package also ships a built-in TMA overlay and applies it after cloning
5158

5259
- `opencode.json` is shipped by the template for OpenCode.
5360
- `.mcp.json` is shipped by the template for Claude Code.
61+
- `AGENTS.md` is shipped by the template for repo-level AI agent instructions.
62+
- `CLAUDE.md` is shipped by the template for Claude Code project memory.
63+
- `.agents/skills/tma-knowledge-search` is shipped by the template as the local TMA knowledge-search skill for compatible agents.
5464
- if `codex` is installed locally, bootstrap also registers the same MCP server in
5565
the global Codex MCP config automatically.
66+
- bootstrap also mirrors `tma-knowledge-search` into `~/.codex/skills` so Codex can discover the same skill natively.
5667

5768
## Development
5869

packages/app/src/core/bootstrap.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ export interface BootstrapClaim {
4141
readonly telegramMiniAppUrl?: string
4242
readonly deviceSecret: string
4343
readonly mcpApiKey: string
44+
readonly apiToken?: string
4445
readonly localPort: number
4546
}
4647

@@ -210,6 +211,7 @@ export const buildGeneratedFiles = (
210211
deviceSecret: claim.deviceSecret,
211212
mcpServerUrl,
212213
mcpApiKey: claim.mcpApiKey,
214+
...(claim.apiToken ? { apiToken: claim.apiToken } : {}),
213215
}
214216

215217
const env = {
@@ -223,6 +225,7 @@ export const buildGeneratedFiles = (
223225
SPAWNDOCK_PROJECT_ID: claim.projectId,
224226
SPAWNDOCK_PROJECT_SLUG: claim.projectSlug,
225227
SPAWNDOCK_ALLOWED_DEV_ORIGINS: claim.previewOrigin,
228+
...(claim.apiToken ? { SPAWNDOCK_API_TOKEN: claim.apiToken } : {}),
226229
}
227230

228231
return [

packages/app/src/shell/bootstrap.ts

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
1-
import { existsSync, mkdirSync, readFileSync, readdirSync, writeFileSync } from "node:fs"
1+
import { existsSync, mkdirSync, readFileSync, readdirSync, rmSync, writeFileSync } from "node:fs"
22
import {
33
spawnSync,
44
type SpawnSyncOptionsWithStringEncoding,
55
type SpawnSyncReturns,
66
} from "node:child_process"
7+
import { homedir } from "node:os"
78
import { fileURLToPath } from "node:url"
89
import { dirname, join, resolve } from "node:path"
910
import { Console, Effect } from "effect"
@@ -24,6 +25,7 @@ import {
2425
} from "../core/bootstrap.js"
2526

2627
const TEMPLATE_OVERLAY_DIR = resolveTemplateOverlayDir()
28+
const TMA_KNOWLEDGE_SKILL_NAME = "tma-knowledge-search"
2729

2830
interface BootstrapPreflightTarget {
2931
readonly projectDir: string
@@ -314,6 +316,7 @@ const registerAgentIntegrations = (
314316
): Effect.Effect<ReadonlyArray<string>, Error> =>
315317
Effect.gen(function* () {
316318
const integrations: string[] = [...DEFAULT_MCP_AGENTS]
319+
yield* installCodexSkill(projectDir)
317320
const mcpServerUrl = buildMcpServerUrl(claim.controlPlaneUrl)
318321
const codexRegistered = yield* registerCodexIntegration(projectDir, mcpServerUrl, claim.mcpApiKey)
319322

@@ -324,6 +327,29 @@ const registerAgentIntegrations = (
324327
return integrations
325328
})
326329

330+
const installCodexSkill = (projectDir: string): Effect.Effect<boolean, never> =>
331+
Effect.try({
332+
try: () => {
333+
const sourceDir = join(projectDir, ".agents", "skills", TMA_KNOWLEDGE_SKILL_NAME)
334+
if (!existsSync(sourceDir)) {
335+
return false
336+
}
337+
338+
const codexHome = process.env["CODEX_HOME"]
339+
const codexRoot = codexHome?.length
340+
? codexHome
341+
: join(homedir(), ".codex")
342+
const targetDir = join(codexRoot, "skills", TMA_KNOWLEDGE_SKILL_NAME)
343+
344+
rmSync(targetDir, { recursive: true, force: true })
345+
mkdirSync(dirname(targetDir), { recursive: true })
346+
copyOverlayTreeSync(sourceDir, targetDir)
347+
348+
return true
349+
},
350+
catch: toError,
351+
}).pipe(Effect.catchAll(() => Effect.succeed(false)))
352+
327353
const registerCodexIntegration = (
328354
projectDir: string,
329355
mcpServerUrl: string,
@@ -407,6 +433,9 @@ const parseClaimResponse = (
407433
const mcpApiKey =
408434
readString(input, "mcpApiKey") ??
409435
readString(input, "mcpToken")
436+
const apiToken =
437+
readString(input, "apiToken") ??
438+
readString(input, "api_token")
410439
const localPort =
411440
readNumber(input, "localPort") ??
412441
(typeof fallbackLocalPort === "number" ? fallbackLocalPort : 3000)
@@ -429,6 +458,7 @@ const parseClaimResponse = (
429458
...(telegramMiniAppUrl ? { telegramMiniAppUrl } : {}),
430459
deviceSecret,
431460
mcpApiKey,
461+
...(apiToken ? { apiToken } : {}),
432462
localPort,
433463
}
434464
}
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
---
2+
name: tma-knowledge-search
3+
description: Search the SpawnDock TMA knowledge API for Telegram Mini App and SpawnDock-specific implementation guidance. Use when Codex needs authoritative TMA workflow details, Telegram WebApp API usage, SpawnDock TMA template behavior, or wants to verify how a feature should be built for Telegram Mini Apps before answering or coding.
4+
---
5+
6+
# TMA Knowledge Search
7+
8+
Use this skill when local repo context is not enough for a Telegram Mini App question and the answer should come from the SpawnDock TMA knowledge base.
9+
10+
## Workflow
11+
12+
1. Form a focused English query about the TMA implementation detail you need.
13+
2. Run `scripts/search_tma_knowledge.py "<query>"`.
14+
3. Read the returned `answer` first, then inspect any `sources`.
15+
4. Use the API result as the primary TMA-specific reference in your answer or implementation plan.
16+
17+
## Query Rules
18+
19+
- Prefer English queries even if the user writes in another language.
20+
- Ask about one concrete problem at a time.
21+
- Include key TMA terms in the query: `Telegram Mini App`, `WebApp`, `MainButton`, `theme`, `viewport`, `SpawnDock`, `Next.js template`, and similar domain words when relevant.
22+
- Re-query with a narrower prompt if the first result is generic.
23+
- Avoid unnecessary repeat calls: the endpoint can rate-limit quickly on the free tier.
24+
25+
## Output Handling
26+
27+
- Treat the API response as TMA-specific guidance, not as a generic web best-practices source.
28+
- If the API returns no useful sources, say that clearly and fall back to repo code or official Telegram docs as needed.
29+
- Keep citations lightweight: mention the knowledge API result and summarize the relevant guidance rather than dumping raw JSON.
30+
31+
## Resources
32+
33+
- `scripts/search_tma_knowledge.py`: sends the POST request and prints a readable summary or raw JSON.
34+
- The script automatically uses `SPAWNDOCK_API_TOKEN`, `API_TOKEN`, or the nearest `spawndock.config.json` `apiToken` when available.
35+
- `references/api.md`: request and response contract for the knowledge endpoint.
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
interface:
2+
display_name: "TMA Knowledge Search"
3+
short_description: "Search TMA implementation knowledge"
4+
default_prompt: "Use $tma-knowledge-search to look up Telegram Mini App and SpawnDock TMA implementation details before answering."
5+
6+
policy:
7+
allow_implicit_invocation: true
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
# SpawnDock TMA Knowledge API
2+
3+
Use this endpoint when you need Telegram Mini App or SpawnDock-specific implementation guidance:
4+
5+
```bash
6+
curl -X POST \
7+
'https://spawn-dock.w3voice.net/knowledge/api/v1/search' \
8+
-H 'accept: application/json' \
9+
-H 'Content-Type: application/json' \
10+
-d '{
11+
"query": "How do I use MainButton in a Telegram Mini App?",
12+
"locale": "en"
13+
}'
14+
```
15+
16+
## Request
17+
18+
- Method: `POST`
19+
- URL: `https://spawn-dock.w3voice.net/knowledge/api/v1/search`
20+
- Content-Type: `application/json`
21+
- Body fields:
22+
- `query` string, required
23+
- `locale` string, optional in practice for the script, default `en`
24+
25+
## Observed response shape
26+
27+
```json
28+
{
29+
"answer": "Human-readable answer",
30+
"sources": [],
31+
"meta": {
32+
"locale_requested": "en"
33+
}
34+
}
35+
```
36+
37+
## Notes
38+
39+
- The skill defaults to `locale=en`.
40+
- `Authorization: Bearer <API_TOKEN>` is optional and enables the higher-tier limits when the token is valid.
41+
- SpawnDock bootstrap can write that token into `spawndock.config.json` as `apiToken` and into `.env.local` as `SPAWNDOCK_API_TOKEN`.
42+
- The API can return an empty `sources` array.
43+
- Use the answer as TMA-specific guidance, then inspect `sources` when present.
44+
- The endpoint can return `429 rate_limit exceeded (minute)` after a small number of requests on the free tier.

0 commit comments

Comments
 (0)