Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,11 +31,18 @@ npx --yes github:SpawnDock/create#main --token <pairing-token> [project-dir]
- `spawndock.dev-tunnel.json`
- `public/tonconnect-manifest.json`

`spawndock.config.json` may include `apiToken`, and `.env.local` may include
`SPAWNDOCK_API_TOKEN`, so the bundled TMA knowledge-search skill can use the
authenticated API tier immediately after bootstrap.

## Built-in Overlay

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

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

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

## Development

Expand Down
3 changes: 3 additions & 0 deletions packages/app/src/core/bootstrap.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ export interface BootstrapClaim {
readonly telegramMiniAppUrl?: string
readonly deviceSecret: string
readonly mcpApiKey: string
readonly apiToken?: string
readonly localPort: number
}

Expand Down Expand Up @@ -210,6 +211,7 @@ export const buildGeneratedFiles = (
deviceSecret: claim.deviceSecret,
mcpServerUrl,
mcpApiKey: claim.mcpApiKey,
...(claim.apiToken ? { apiToken: claim.apiToken } : {}),
}

const env = {
Expand All @@ -223,6 +225,7 @@ export const buildGeneratedFiles = (
SPAWNDOCK_PROJECT_ID: claim.projectId,
SPAWNDOCK_PROJECT_SLUG: claim.projectSlug,
SPAWNDOCK_ALLOWED_DEV_ORIGINS: claim.previewOrigin,
...(claim.apiToken ? { SPAWNDOCK_API_TOKEN: claim.apiToken } : {}),
}

return [
Expand Down
32 changes: 31 additions & 1 deletion packages/app/src/shell/bootstrap.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
import { existsSync, mkdirSync, readFileSync, readdirSync, writeFileSync } from "node:fs"
import { existsSync, mkdirSync, readFileSync, readdirSync, rmSync, writeFileSync } from "node:fs"
import {
spawnSync,
type SpawnSyncOptionsWithStringEncoding,
type SpawnSyncReturns,
} from "node:child_process"
import { homedir } from "node:os"
import { fileURLToPath } from "node:url"
import { dirname, join, resolve } from "node:path"
import { Console, Effect } from "effect"
Expand All @@ -24,6 +25,7 @@ import {
} from "../core/bootstrap.js"

const TEMPLATE_OVERLAY_DIR = resolveTemplateOverlayDir()
const TMA_KNOWLEDGE_SKILL_NAME = "tma-knowledge-search"

interface BootstrapPreflightTarget {
readonly projectDir: string
Expand Down Expand Up @@ -314,6 +316,7 @@ const registerAgentIntegrations = (
): Effect.Effect<ReadonlyArray<string>, Error> =>
Effect.gen(function* () {
const integrations: string[] = [...DEFAULT_MCP_AGENTS]
yield* installCodexSkill(projectDir)
const mcpServerUrl = buildMcpServerUrl(claim.controlPlaneUrl)
const codexRegistered = yield* registerCodexIntegration(projectDir, mcpServerUrl, claim.mcpApiKey)

Expand All @@ -324,6 +327,29 @@ const registerAgentIntegrations = (
return integrations
})

const installCodexSkill = (projectDir: string): Effect.Effect<boolean, never> =>
Effect.try({
try: () => {
const sourceDir = join(projectDir, ".agents", "skills", TMA_KNOWLEDGE_SKILL_NAME)
if (!existsSync(sourceDir)) {
return false
}

const codexHome = process.env["CODEX_HOME"]
const codexRoot = codexHome?.length
? codexHome
: join(homedir(), ".codex")
const targetDir = join(codexRoot, "skills", TMA_KNOWLEDGE_SKILL_NAME)

rmSync(targetDir, { recursive: true, force: true })
mkdirSync(dirname(targetDir), { recursive: true })
copyOverlayTreeSync(sourceDir, targetDir)

return true
},
catch: toError,
}).pipe(Effect.catchAll(() => Effect.succeed(false)))

const registerCodexIntegration = (
projectDir: string,
mcpServerUrl: string,
Expand Down Expand Up @@ -407,6 +433,9 @@ const parseClaimResponse = (
const mcpApiKey =
readString(input, "mcpApiKey") ??
readString(input, "mcpToken")
const apiToken =
readString(input, "apiToken") ??
readString(input, "api_token")
const localPort =
readNumber(input, "localPort") ??
(typeof fallbackLocalPort === "number" ? fallbackLocalPort : 3000)
Expand All @@ -429,6 +458,7 @@ const parseClaimResponse = (
...(telegramMiniAppUrl ? { telegramMiniAppUrl } : {}),
deviceSecret,
mcpApiKey,
...(apiToken ? { apiToken } : {}),
localPort,
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
---
name: tma-knowledge-search
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.
---

# TMA Knowledge Search

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.

## Workflow

1. Form a focused English query about the TMA implementation detail you need.
2. Run `scripts/search_tma_knowledge.py "<query>"`.
3. Read the returned `answer` first, then inspect any `sources`.
4. Use the API result as the primary TMA-specific reference in your answer or implementation plan.

## Query Rules

- Prefer English queries even if the user writes in another language.
- Ask about one concrete problem at a time.
- Include key TMA terms in the query: `Telegram Mini App`, `WebApp`, `MainButton`, `theme`, `viewport`, `SpawnDock`, `Next.js template`, and similar domain words when relevant.
- Re-query with a narrower prompt if the first result is generic.
- Avoid unnecessary repeat calls: the endpoint can rate-limit quickly on the free tier.

## Output Handling

- Treat the API response as TMA-specific guidance, not as a generic web best-practices source.
- If the API returns no useful sources, say that clearly and fall back to repo code or official Telegram docs as needed.
- Keep citations lightweight: mention the knowledge API result and summarize the relevant guidance rather than dumping raw JSON.

## Resources

- `scripts/search_tma_knowledge.py`: sends the POST request and prints a readable summary or raw JSON.
- The script automatically uses `SPAWNDOCK_API_TOKEN`, `API_TOKEN`, or the nearest `spawndock.config.json` `apiToken` when available.
- `references/api.md`: request and response contract for the knowledge endpoint.
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
interface:
display_name: "TMA Knowledge Search"
short_description: "Search TMA implementation knowledge"
default_prompt: "Use $tma-knowledge-search to look up Telegram Mini App and SpawnDock TMA implementation details before answering."

policy:
allow_implicit_invocation: true
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
# SpawnDock TMA Knowledge API

Use this endpoint when you need Telegram Mini App or SpawnDock-specific implementation guidance:

```bash
curl -X POST \
'https://spawn-dock.w3voice.net/knowledge/api/v1/search' \
-H 'accept: application/json' \
-H 'Content-Type: application/json' \
-d '{
"query": "How do I use MainButton in a Telegram Mini App?",
"locale": "en"
}'
```

## Request

- Method: `POST`
- URL: `https://spawn-dock.w3voice.net/knowledge/api/v1/search`
- Content-Type: `application/json`
- Body fields:
- `query` string, required
- `locale` string, optional in practice for the script, default `en`

## Observed response shape

```json
{
"answer": "Human-readable answer",
"sources": [],
"meta": {
"locale_requested": "en"
}
}
```

## Notes

- The skill defaults to `locale=en`.
- `Authorization: Bearer <API_TOKEN>` is optional and enables the higher-tier limits when the token is valid.
- SpawnDock bootstrap can write that token into `spawndock.config.json` as `apiToken` and into `.env.local` as `SPAWNDOCK_API_TOKEN`.
- The API can return an empty `sources` array.
- Use the answer as TMA-specific guidance, then inspect `sources` when present.
- The endpoint can return `429 rate_limit exceeded (minute)` after a small number of requests on the free tier.
Loading