Use this skill to build an agent with FastAgent and serve it — starting from nothing, from files that already exist, or inside an existing application.
Goal
Inspect the project first, preserve anything that already exists, and make the smallest change that gives the user a running agent: locally, embedded in their app, connected to a channel, or deployed.
Choose your path
Decide which job this is before touching anything:
- New agent, empty directory. Nothing agent-shaped exists yet. Run
fastagent init <dir>(or init the current directory), then flesh outpersona.md, skills, and tools from what the user wants. - An existing directory becomes the agent. The directory holds what the agent works on or with:
AGENTS.md, markdown context, skills, tools — or just the projects the agent should manage (a parent directory of repos counts; it needs no agent-shaped files yet). Do not restructure it: runfastagent initin place; init never overwrites existing files and adopts them as the definition. - Embed an agent into an existing application. The project is an app (framework config, routes, its own toolchain). Initialize — init chooses
./agentwithconfig.agentDirautomatically when the root is claimed — then mount the agent in the app’s own route withcreatePiAgentFromDefinition+createInvokeHandler. The app keeps auth, database, and deployment.
All three paths continue with the same steps below: inspect, authenticate, initialize once, test, then connect channels or deploy.
Mental model
- The directory is the agent: optional
persona.mdfor identity,skills/,tools/,channels/,schedules/, markdown context, andAGENTS.mdfor project context. - An
AGENTS.mddoes not make a directory a FastAgent workspace. Afastagent.config.*file does. - FastAgent can run the directory locally, embed it in an app, connect it to GitHub, Telegram, or Slack, expose it over HTTP, or put it behind a custom channel.
- Do not invent a new project layout unless the user asks. Prefer the existing directory.
Inspect before changing anything
- Check whether
fastagent.config.*exists. If it does, the directory is already a workspace; read itsagentDirwhen present. - Check for
persona.md,AGENTS.md,skills/,tools/,channels/, andschedules/at the root and under any configuredagentDir. - If code tools are present, check whether
package.jsonsets"type": "module". - Ask before choosing a model provider, adding credentials, or changing the existing layout.
Handle authentication and models explicitly
You are non-interactive, so do not rely on prompts you cannot answer.
- A model must be explicit. Without one,
dev,start,invoke,fire, andchatopen a picker on a TTY and fail in a non-TTY withmissing model.deployalso opens the picker on a TTY, but non-interactively it does NOT saymissing model: plan mode warns, and--runstops at the model-travel gate (“no model in fastagent.config.ts”). fastagent loginis also interactive. Ask the user to run it in a terminal inside the workspace; it writes project-level.fastagent/auth.json, and credentials written in another directory are not visible here.- Alternatively, ask the user for a provider API key and put it in
.envonly with permission. - List available specifications with
fastagent models. - Always pass
--model provider/id, setFASTAGENT_MODEL, or writemodelinfastagent.config.*. - Never commit
.env, credentials, sessions, or.fastagent/machine state.
Know which commands exit
Use commands that exit for verification:
fastagent info
fastagent models
fastagent invoke "hello" --model provider/id
fastagent tool <name> '<json>'fastagent dev and fastagent start are long-running servers. Do not run them in the foreground and wait indefinitely. Background them with a cleanup path, or ask the user to run them.
Initialize once
Run:
fastagent init <dir>Run init in the directory the agent must see and act on — its location sets the agent’s working directory, project context, and what deploy bakes into the image. Never create a fresh subdirectory and init inside it: that scopes the agent to an empty folder, cut off from the projects around it. If a subdirectory layout is needed, init at the root and let init choose ./agent + config.agentDir itself.
The default directory is the current directory. init:
- scaffolds
persona.md, an example skill and tool, and config; - never overwrites existing files;
- keeps an existing
AGENTS.mdas project context; - refuses a directory that already has
fastagent.config.*.
FastAgent chooses the layout on the first run:
- flat by default;
./agentwithconfig.agentDirwhen an existing toolchain or deployment already claims the root, including framework config,tsconfig,go.mod,pyproject.toml,Cargo.toml, Docker/Fly/Railway config, or occupiedtools/,channels/, orskills/directories.
Override only on the first run with --flat or --agent-dir <name>. To change it later, move the files and update or remove config.agentDir.
Then run:
fastagent infoRead what the directory assembles into and fix only reported problems.
Test locally
Prefer a single turn that exits:
fastagent invoke "hello" --model provider/idTest a tool without a model:
fastagent tool <name> '<json>'Only start a live server when needed:
fastagent dev --model provider/idBackground it or ask the user to run it, then send a turn to POST /invoke.
For an interactive session, ask the user to run fastagent chat in a terminal: it opens the same assembled agent in pi’s TUI, with the same model, tool, and skill resolution as dev.
Add tools
Put tools in tools/<name>.ts. Use defineTool and z from @fastagent-sh/fastagent, then test the tool directly:
fastagent tool <name> '<json>'To vendor an existing Agent Skills skill instead of writing one, run fastagent add skill <source> with a git ref (owner/repo/path), a local path, or a bare name from your global skill dirs (~/.agents/skills, ~/.pi/agent/skills).
Add channels
A channels/*.ts, *.js, or *.mjs file is enabled by its presence. A declared channel that fails to load must make dev or start fail; fix it rather than accepting a fallback route.
To disable one, rename it to something like channels/telegram.ts.disabled. Do not invent a second config flag.
GitHub
fastagent add githubEdit channels/github.ts so on(event) maps real GitHub events to { session, text } intents. Use fastagent dev --tunnel for local webhook testing.
Telegram
fastagent add telegramSet TELEGRAM_BOT_TOKEN and TELEGRAM_SECRET_TOKEN. Use fastagent dev --tunnel for local webhook testing.
Feishu / Lark
fastagent add feishu # Feishu (open.feishu.cn)
fastagent add lark # Lark international (open.larksuite.com)add feishu creates and configures the platform app (a scan-to-confirm flow in the Feishu app) and writes credentials to .env; one manual version-publish click remains in the console. add lark opens the international developer console and guides App ID/Secret setup. Both are interactive — ask the user to run them in a terminal. Use fastagent dev --tunnel for local webhook testing.
Add schedules
Create schedules/<name>.ts:
import { defineSchedule } from "@fastagent-sh/fastagent";
export default defineSchedule({
cron: "0 9 * * *",
tz: "America/New_York",
prompt: "...",
});The filename is the schedule name. The prompt must say where output goes: the scheduler fires the agent, but a plain reply is not delivered anywhere. Delivery is a send tool’s job. A scheduled turn runs outside any chat, so include the target chat ID in the prompt.
fastagent add telegram scaffolds tools/telegram-send.ts, which can send a message or file.
Test without changing cron state:
fastagent fire <name> --model provider/idInspect schedules and prior runs:
fastagent schedule list
fastagent schedule history <name>Cron schedules run only while dev or start is serving. Agent self-scheduling through the built-in wake tool is opt-in with selfSchedule: true in config.
Schedules and self-scheduling require one always-running machine. Do not scale that deployment to zero.
Embed in an application
Use createPiAgentFromDefinition or createPiAgentFromWorkspace, then mount createInvokeHandler(agent) in the application’s route.
Keep authentication, users, database, session ownership, and policy in the host application.
ExecutionEnv is an assembly seam, not a complete sandbox. The pi coding tools and project-context loader are still local; do not claim that injecting env alone isolates a directory agent.
Deploy
Generate host artifacts and a runbook:
fastagent deploy docker # local Compose; add --tunnel for an ephemeral webhook ingress
fastagent deploy fly
fastagent deploy railwayAdd --run to drive Docker Compose or the host CLI to completion.
The model must be in fastagent.config.*. A builder-local --model, FASTAGENT_MODEL, or .env value does not reach the deployed machine and otherwise causes a missing model crash loop.
Declare additional host secrets in config.deploy.secrets, then register channel webhooks at the live URL.
Verify before finishing
-
Run
fastagent info. -
If channels are declared, confirm every channel loads.
-
Run the smallest useful command that exits, usually:
fastagent invoke "hello" --model provider/id -
Do not leave
devorstartrunning in the foreground. -
Do not commit
.env, credentials, sessions, or.fastagent/state. -
If a command fails, read Troubleshooting before guessing.

