Skip to content

Commit 07b6ca7

Browse files
authored
docs: add agent guidance to TMA template (#15)
* docs: add agent guidance to TMA template * feat(template): add TMA knowledge skill and agent memory
1 parent e73bbf3 commit 07b6ca7

8 files changed

Lines changed: 356 additions & 1 deletion

File tree

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.
Lines changed: 183 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,183 @@
1+
#!/usr/bin/env python3
2+
import argparse
3+
import json
4+
import os
5+
import sys
6+
import time
7+
import urllib.error
8+
import urllib.request
9+
from pathlib import Path
10+
11+
12+
API_URL = "https://spawn-dock.w3voice.net/knowledge/api/v1/search"
13+
14+
15+
def parse_args() -> argparse.Namespace:
16+
parser = argparse.ArgumentParser(
17+
description="Query the SpawnDock TMA knowledge API."
18+
)
19+
parser.add_argument("query", help="Knowledge search query")
20+
parser.add_argument("--locale", default="en", help="Response locale (default: en)")
21+
parser.add_argument(
22+
"--api-token",
23+
help="Optional Bearer token override. Defaults to SPAWNDOCK_API_TOKEN/API_TOKEN or spawndock.config.json",
24+
)
25+
parser.add_argument(
26+
"--config",
27+
help="Optional path to spawndock.config.json. Defaults to the nearest config found from cwd upward.",
28+
)
29+
parser.add_argument(
30+
"--timeout",
31+
type=float,
32+
default=20.0,
33+
help="HTTP timeout in seconds (default: 20)",
34+
)
35+
parser.add_argument(
36+
"--raw",
37+
action="store_true",
38+
help="Print raw JSON response instead of a formatted summary",
39+
)
40+
parser.add_argument(
41+
"--retries",
42+
type=int,
43+
default=2,
44+
help="Retry count for transient HTTP 5xx failures (default: 2)",
45+
)
46+
return parser.parse_args()
47+
48+
49+
def find_config_path(explicit_path: str | None) -> Path | None:
50+
if explicit_path:
51+
path = Path(explicit_path).expanduser()
52+
return path if path.is_file() else None
53+
54+
for base in [Path.cwd(), *Path.cwd().parents]:
55+
candidate = base / "spawndock.config.json"
56+
if candidate.is_file():
57+
return candidate
58+
59+
return None
60+
61+
62+
def read_config_api_token(config_path: Path | None) -> str | None:
63+
if config_path is None:
64+
return None
65+
66+
try:
67+
data = json.loads(config_path.read_text(encoding="utf-8"))
68+
except (OSError, json.JSONDecodeError):
69+
return None
70+
71+
token = data.get("apiToken")
72+
return token.strip() if isinstance(token, str) and token.strip() else None
73+
74+
75+
def resolve_api_token(cli_token: str | None, config_path: Path | None) -> str | None:
76+
if cli_token and cli_token.strip():
77+
return cli_token.strip()
78+
79+
for key in ("SPAWNDOCK_API_TOKEN", "API_TOKEN"):
80+
value = os.environ.get(key, "").strip()
81+
if value:
82+
return value
83+
84+
return read_config_api_token(config_path)
85+
86+
87+
def request_knowledge(
88+
query: str,
89+
locale: str,
90+
timeout: float,
91+
retries: int,
92+
api_token: str | None,
93+
) -> dict:
94+
payload = json.dumps({"query": query, "locale": locale}).encode("utf-8")
95+
for attempt in range(retries + 1):
96+
headers = {
97+
"accept": "application/json",
98+
"content-type": "application/json",
99+
}
100+
if api_token:
101+
headers["authorization"] = f"Bearer {api_token}"
102+
103+
req = urllib.request.Request(
104+
API_URL,
105+
data=payload,
106+
headers=headers,
107+
method="POST",
108+
)
109+
try:
110+
with urllib.request.urlopen(req, timeout=timeout) as response:
111+
charset = response.headers.get_content_charset() or "utf-8"
112+
return json.loads(response.read().decode(charset))
113+
except urllib.error.HTTPError as exc:
114+
if exc.code < 500 or attempt == retries:
115+
raise
116+
time.sleep(min(2**attempt, 5))
117+
118+
raise RuntimeError("Unreachable retry loop")
119+
120+
121+
def format_response(data: dict) -> str:
122+
lines: list[str] = []
123+
answer = data.get("answer")
124+
sources = data.get("sources") or []
125+
meta = data.get("meta") or {}
126+
127+
lines.append("Answer:")
128+
lines.append(answer if answer else "(empty)")
129+
130+
if sources:
131+
lines.append("")
132+
lines.append("Sources:")
133+
for idx, source in enumerate(sources, start=1):
134+
if isinstance(source, dict):
135+
title = source.get("title") or source.get("name") or f"Source {idx}"
136+
url = source.get("url") or source.get("href") or ""
137+
snippet = source.get("snippet") or source.get("text") or ""
138+
line = f"{idx}. {title}"
139+
if url:
140+
line += f" - {url}"
141+
lines.append(line)
142+
if snippet:
143+
lines.append(f" {snippet}")
144+
else:
145+
lines.append(f"{idx}. {source}")
146+
147+
if meta:
148+
lines.append("")
149+
lines.append("Meta:")
150+
lines.append(json.dumps(meta, ensure_ascii=False, sort_keys=True))
151+
152+
return "\n".join(lines)
153+
154+
155+
def main() -> int:
156+
args = parse_args()
157+
config_path = find_config_path(args.config)
158+
api_token = resolve_api_token(args.api_token, config_path)
159+
try:
160+
data = request_knowledge(
161+
args.query,
162+
args.locale,
163+
args.timeout,
164+
args.retries,
165+
api_token,
166+
)
167+
except urllib.error.HTTPError as exc:
168+
body = exc.read().decode("utf-8", errors="replace")
169+
print(f"HTTP error: {exc.code}\n{body}", file=sys.stderr)
170+
return 1
171+
except urllib.error.URLError as exc:
172+
print(f"Request failed: {exc}", file=sys.stderr)
173+
return 1
174+
175+
if args.raw:
176+
print(json.dumps(data, ensure_ascii=False, indent=2, sort_keys=True))
177+
else:
178+
print(format_response(data))
179+
return 0
180+
181+
182+
if __name__ == "__main__":
183+
raise SystemExit(main())

AGENTS.md

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
# SpawnDock TMA Template
2+
3+
You are an AI agent working inside the SpawnDock Telegram Mini App template.
4+
5+
Your job is to build and improve a production-ready Telegram Mini App in this repository. Treat this as a real TMA project, not as a generic web app and not as a docs-only exercise.
6+
7+
## Default Mode
8+
9+
- Work end-to-end inside the repo: design, implement, and validate when the user is asking for a result.
10+
- Prefer concrete code and file changes over abstract advice unless the user explicitly wants brainstorming only.
11+
- If requirements are incomplete, choose the smallest sensible TMA-first default and keep moving.
12+
- Ask a question only when missing information would materially change the product flow or create a high risk of doing the wrong work.
13+
14+
## Project Contract
15+
16+
- Preserve the current stack: Next.js, App Router, TypeScript, SpawnDock scripts, and the existing Telegram/TMA integrations.
17+
- Do not replace the framework, routing model, or core dev workflow unless the user explicitly asks for that change.
18+
- Prefer changes that fit the existing `src/app` structure, shared styling approach, and `spawndock/*.mjs` wrappers.
19+
- Use `pnpm` commands, not `npm`, unless a task explicitly requires otherwise.
20+
21+
## TMA Rules
22+
23+
- Always treat the app as a Telegram Mini App first.
24+
- Prefer mobile-first, touch-first UX and layouts that work well inside Telegram WebView.
25+
- Use Telegram WebApp APIs where appropriate: `ready`, `expand`, `MainButton`, `BackButton`, `themeParams`, `HapticFeedback`, `openLink`, `openTelegramLink`, `sendData`, and viewport APIs.
26+
- Respect Telegram theming. Do not hardcode colors where Telegram theme params should drive the UI.
27+
- Avoid browser patterns that are fragile inside Telegram WebView: `alert()`, `confirm()`, `prompt()`, `target=\"_blank\"`, `window.open()`, and desktop-first navigation patterns.
28+
- Do not introduce `BrowserRouter`-style assumptions for TMA navigation.
29+
30+
## TMA Knowledge Search
31+
32+
- When local repo context is not enough for a Telegram Mini App or SpawnDock-specific implementation question, use the local `tma-knowledge-search` skill before generic web search.
33+
- In generated projects the local skill lives at `.agents/skills/tma-knowledge-search`.
34+
- Query the skill in English and ask one focused implementation question at a time.
35+
- Read the returned `answer` first, then inspect `sources` when they are present.
36+
- SpawnDock bootstrap also mirrors the same skill into `~/.codex/skills/tma-knowledge-search` when possible so Codex can discover it natively.
37+
38+
## Dev Flow
39+
40+
- `pnpm run dev` is the primary local workflow. It starts the Next.js dev server and the SpawnDock dev tunnel together.
41+
- `pnpm run dev:next` starts only the local Next.js server.
42+
- `pnpm run dev:tunnel` starts only the SpawnDock tunnel client.
43+
- `pnpm run agent` starts the Next.js server, the tunnel, and the local agent runtime launcher.
44+
- If the user asks to run the project, preview the app, or get a tunnel URL, prefer `pnpm run dev`.
45+
- Do not describe `pnpm run dev` as “just Next.js dev”; in this template it is the combined app-plus-tunnel flow.
46+
- If `spawndock.config.json` or `spawndock.dev-tunnel.json` is missing or invalid, the project is probably not fully bootstrapped yet.
47+
48+
## Implementation Expectations
49+
50+
- Build only what is needed for the requested feature set.
51+
- Keep the architecture simple, shippable, and easy to extend.
52+
- Reuse existing components and patterns before introducing new abstractions.
53+
- Add loading, empty, and error states for user-facing flows when they matter.
54+
- Make the smallest set of changes that fully solves the task.
55+
56+
## Validation
57+
58+
- Run the narrowest relevant checks after changes.
59+
- Prefer `pnpm run build` for code validation.
60+
- Use `pnpm run dev` when the task depends on runtime behavior, preview behavior, or the SpawnDock tunnel.
61+
- If you could not run a relevant check, say so explicitly.
62+
63+
## Success Criteria
64+
65+
- The result fits the current template and preserves its workflow.
66+
- The app behaves like a proper Telegram Mini App and respects Telegram constraints.
67+
- The main local development flow, especially `pnpm run dev`, remains intact.
68+
- The code is ready for real iteration, not just for demo output.

CLAUDE.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
# SpawnDock TMA Template
2+
3+
- Treat this repository as a Telegram Mini App project first, not as a generic web app.
4+
- Prefer `pnpm run dev` for the main local workflow because it starts both Next.js and the SpawnDock dev tunnel.
5+
- When local repo context is not enough for a Telegram Mini App or SpawnDock-specific implementation question, use the local `tma-knowledge-search` skill at `.agents/skills/tma-knowledge-search`.
6+
- Query that skill in English, keep the question focused, and use its answer before falling back to generic web guidance.

README.md

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,15 @@ npx -y @spawn-dock/create@beta --token <pairing-token> [project-dir]
3232
- `pnpm run publish:github-pages` exports the app and deploys it to GitHub Pages.
3333
- `pnpm run start` starts the production Next.js server.
3434

35+
## Agent Guidance
36+
37+
- `AGENTS.md` contains the base system instructions for AI agents working inside this template.
38+
- `CLAUDE.md` provides Claude Code project memory and points it to the local TMA knowledge skill.
39+
- `.agents/skills/tma-knowledge-search` contains the local Telegram Mini App / SpawnDock knowledge-search skill used by compatible agents.
40+
- Agents should treat `pnpm run dev` as the main local flow because it starts both Next.js and the SpawnDock dev tunnel.
41+
- Use `pnpm run dev:next` only when you explicitly want the local app server without the tunnel.
42+
- SpawnDock bootstrap also mirrors the same skill into `~/.codex/skills/tma-knowledge-search` when preparing a local Codex setup.
43+
3544
## SpawnDock Flow
3645

3746
The starter expects a bootstrap step that writes `spawndock.config.json` and
@@ -42,7 +51,9 @@ ready to connect to `@spawn-dock/mcp` via `/mcp/sse`.
4251
## Local Config
4352

4453
- `spawndock.config.json` contains preview/runtime data for the app.
54+
- `spawndock.config.json` can also include `apiToken` for the TMA knowledge-search skill.
4555
- `spawndock.dev-tunnel.json` contains tunnel connection data.
56+
- `.env.local` can include `SPAWNDOCK_API_TOKEN` for the same knowledge-search access.
4657
- `opencode.json` is generated during bootstrap for OpenCode.
4758
- `.mcp.json` is generated during bootstrap for Claude Code.
4859
- `spawndock/mcp.mjs` resolves `mcpServerUrl` from `spawndock.config.json`.

spawndock.config.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,5 +10,6 @@
1010
"previewHost": "",
1111
"localPort": 3000,
1212
"mcpServerUrl": "",
13-
"mcpApiKey": ""
13+
"mcpApiKey": "",
14+
"apiToken": ""
1415
}

0 commit comments

Comments
 (0)