Skip to content

Releases: fastagent-sh/fastagent

v0.12.0 — public launch

Choose a tag to compare

@kid7st kid7st released this 10 Jul 10:34

FastAgent is now public at fastagent-sh/fastagent and published under the @fastagent-sh npm scope.

Highlights

  • Explicit package boundaries — use @fastagent-sh/fastagent/core for the engine-neutral Agent Handler contract and hosting helpers, or /pi for the pi reference implementation. The root package remains the convenient aggregate API.
  • Fail-closed channels — an enabled channel that cannot load or collides with another route now fails dev / start; it can no longer silently disappear and expose the fallback /invoke endpoint. Rename a file to *.disabled to turn it off.
  • Safer skill updatesfastagent add skill --update preserves the previous copy across interrupted or failed updates.
  • Release confidence — Node 22/24/26, packed-package installation, and Bun 1.3 are exercised in CI; releases verify tag/version alignment and publish with npm provenance.
  • Documentation reset — the public docs now distinguish the engine-neutral contract, pi reference implementation, execution environment seam, and runtime isolation responsibilities.

Install

npm i -g @fastagent-sh/fastagent
fastagent init my-agent
cd my-agent
fastagent dev

Full log: v0.11.0...v0.12.0

v0.11.0 — time triggers + serve an existing repo as a coding agent

Choose a tag to compare

@kid7st kid7st released this 09 Jul 06:52

Two feature waves since 0.10.3: time triggers (schedules + self-scheduling) and serving an existing repo as a coding agent (persona/agentDir/scaffold/deploy). One breaking change, called out below.

⏰ Time triggers

  • schedules/ — drop defineSchedule({ cron, prompt }) files in your agent dir; dev/start fire the agent on each cron with a stable per-schedule session. fastagent fire <name> runs one immediately (the authoring loop); fastagent schedule list shows everything that will fire, schedule history the run audit (runs.jsonl).
  • Self-scheduling (opt-in)selfSchedule: true mounts the built-in wake tool so the agent can schedule its own follow-up turns (one-shot or recurring), plus unwake and operator schedule list/cancel. Off by default: autonomy is opt-in.
  • Deploy-aware — time triggers keep one machine running in generated fly.toml (no scale-to-zero dropping a cron), and --run gates on a kept config that would.

🤖 Serve an existing repo as a coding agent

The scenario: your product repo gains a resident agent that reviews, fixes, and answers — without the agent's files colliding with yours.

  • persona.md is the agent's identity (prompt segment ①), replacing AGENTS.md in scaffolds. Your repo's AGENTS.md stays untouched and is read as project context (②) — the two roles no longer share a file.
  • config.agentDir — point the config at ./agent and the agent's own surface (persona/skills/tools/channels/schedules) lives there while the config directory stays the run root (cwd). All commands (dev/start/info/chat/tool/fire/add/deploy) resolve the same split.
  • init detects jurisdiction — a toolchain config, deploy manifest, or occupied tools//channels//skills/ means an existing system claims the tree, so the kit defaults into ./agent (reason printed; --flat / --agent-dir <name> override). The kit self-contains its package.json; a non-empty kit target is refused with the way out.
  • deploy fly|railway learns the layout (experimental) — generates a kit-namespaced recipe (agent/Dockerfile, agent/fly.toml / agent/railway.json) that bakes the whole repo as the agent's cwd and installs only the kit's deps. Write-back mechanics ship in the image (git + deploy.secrets); the policy (push vs PR) belongs to persona.md. A host's root .dockerignore is never overwritten — even with --force. Not yet verified end-to-end on a real host; the runbook is the supported path (--run is gated).

⚠️ Breaking

  • A symlinked agentDir now refuses to load (including a symlink in an intermediate segment). Previously it "worked" while dev's watch silently never saw edits — the link target can escape the config directory. Migration: point agentDir at the real path. Also new: a declared agentDir that doesn't exist is refused at load (a typo used to silently serve an empty agent).

Fixes & hardening

  • fire discovers schedules from agentDir (was: run root) — the same set dev/start serve.
  • dev watch includes schedules/; editing a schedule no longer keeps the old cron firing silently.
  • Telegram: a user turn colliding with an external lease holder (wake) busy-waits instead of failing.
  • HTTP host: no request path can crash the server via unhandled rejection.
  • .env loading unified (env.ts); tunnel's best-effort .env read fixed.
  • Docs: deployment guide (docs/deploy.md), time-trigger guide, llms.txt raw links.

Full log: v0.10.3...v0.11.0

v0.10.3

Choose a tag to compare

@kid7st kid7st released this 07 Jul 08:10

B-mode DevX, from turning a real Bun repo into a deployed agent from scratch.

  • init adopts an existing AGENTS.md repo instead of refusing (adds config + secret-safe .gitignore, guides with the right package manager).
  • Bun-aware generated Dockerfile (oven/bun + bun install + bunx fastagent); markdown path stays node.
  • add dep gate + steps are package-manager-aware.
  • models <search> ranks provider matches first; an expired login reports 'expired/unusable → login' not '(none found)'; login fails fast in a non-TTY.

Behavior change: the generated Dockerfile no longer passes --omit=dev (a repo-as-agent needs its devDependencies). No other breaking changes.

v0.10.2

Choose a tag to compare

@kid7st kid7st released this 07 Jul 06:29

fastagent now runs under Bun, not only Node.

  • proxy.ts imported { install } from undici (missing in Bun's shim) — a link-time crash. Namespace import + Bun guard (Bun's native fetch honors proxy env + gzip).
  • process.loadEnvFile (Node-only) → a portable loadEnvFile matching Node's precedence on both axes, verified differentially.

Verified end-to-end under Bun 1.3: info, invoke, start (/health, telegram). Enables FROM oven/bun + bunx fastagent start. No breaking changes.

v0.10.1

Choose a tag to compare

@kid7st kid7st released this 06 Jul 20:35

Real-world hardening of the deploy line, from deploying an actual repo as a Telegram-reachable agent end-to-end (gaps G1–G8).

  • G1deploy railway --run only provisions on an UNLINKED dir; a foreign/linked project is refused unless --into-linked.
  • G2 — a broken tools//channels/ file is isolated (skipped + warned), never crashing start.
  • G5 — the telegram webhook is registered only after /health is up (deploy race).
  • G4 + G6fastagent.config deploy.secrets/deploy.apt: declare the extra secret env + system packages an agent needs on the box.
  • G3 + G8 — the generated .dockerignore annotates its .git exclusion; convention-dir collisions documented.
  • Internal: runDeployFly/runDeployRailway take an opts object.

No breaking changes. Same OAuth-on-server flow as 0.10.0.

v0.10.0

Choose a tag to compare

@kid7st kid7st released this 06 Jul 10:22

Deploy feature line: fastagent deploy fly and fastagent deploy railway (artifact + runbook generation and --run to drive the host CLI to completion), the model-travel gate (the model must live in fastagent.config.ts to reach the box), OAuth-on-server (--run carries a local OAuth login as FASTAGENT_AUTH_SEED, materialized onto the volume on first boot), the first-run model picker, and an invoke retryable-classification fix.

v0.9.0

Choose a tag to compare

@kid7st kid7st released this 05 Jul 16:11

Changed

  • BREAKING: the channel contract is now ChannelModule = (ctx: ChannelContext) => Routes with
    ctx = { agent, stateRoot }, and the bundled adapters are policy-only factories:
    telegramChannel(opts) / githubChannel(opts) take options (no agent argument) and RETURN a
    ChannelModule that mounts their route (POST /telegram, POST /webhook). A scaffolded channel
    file is now one policy expression — export default telegramChannel({…}) — and agent/stateRoot
    flow from the framework to the adapter without transiting user glue. This also fixes a real anchor
    bug: telegram state was rooted at process.cwd()/.fastagent while engine state used
    <dir>/.fastagent, so fastagent start <dir> from elsewhere split the state home. The
    TelegramChannelOptions.stateDir option is removed: the channel home is always derived from the
    state root, so glue can never silently bypass the operator's one state knob.
    Upgrading: rewrite channels/*.ts to the new one-expression shape (or re-run
    fastagent add <kind>); if you ran fastagent start <dir> with a cwd other than <dir> (or used
    the removed stateDir option), move the old telegram state —
    <old cwd>/.fastagent/channels/telegram/<state root>/channels/telegram/ — before starting,
    or pending turn intents and group-context buffers are silently abandoned.

Added

  • FASTAGENT_STATE_DIR — one knob for the whole machine-state home. .fastagent/ is now formally
    the agent's single-lifecycle state root (sessions, auth.json, channels/<kind>/); the opener
    resolves FASTAGENT_STATE_DIR > <dir>/.fastagent once and everything derives from it, so a
    container mounts ONE volume to keep all durable state (including the Telegram turn intents and
    context buffers that crash/deploy replay depends on — previously impossible to relocate). The finer
    --sessions-dir/FASTAGENT_SESSIONS_DIR and --auth-path/FASTAGENT_AUTH_PATH knobs still
    override their specific path on top (as operator knobs, a relative value resolves against cwd). The
    self-ignore leak guard is now root-based: a custom in-tree root (a FASTAGENT_STATE_DIR inside the
    agent dir) gets its own .gitignore="*", closing a gap where credentials under a non-.fastagent
    in-tree root could show as committable.

  • Durable turn intent for the Telegram channel (L1 crash/deploy recovery). An accepted turn's
    intent is now persisted before the webhook ACK (turns.json) and removed when the turn ends; a turn
    interrupted mid-run — by a crash or a SIGTERM deploy (start has no graceful drain) — is replayed
    on the next start, recovering the ACKed-but-unfinished window Telegram won't redeliver. This is
    at-least-once: replay re-runs the whole turn, so side-effecting tools re-run (safe for a Q&A bot;
    the bar for adding side-effecting ones), and a turn repeatedly interrupted mid-run is dropped after a
    few attempts with a notice to the asker. Exactly-once delivery and deterministic step-replay remain
    L2 (a K-axis backend). This is a deliberate reversal of 0.8.3's "accept the loss" stance — a
    per-process intent log made cheap by the channel's existing atomic-rename state primitive, distinct
    from the queue-level WAL 0.8.3 removed.

v0.8.3

Choose a tag to compare

@kid7st kid7st released this 04 Jul 18:16

Release 0.8.3.

Changed

  • Telegram per-session turn queue is now in-memory (file-backed WAL removed). Single-turn-per-session FIFO unchanged; only restart-durability dropped — consistent with start's no-graceful-drain on SIGTERM. Un-summoned group context buffer stays durable.

Removed

  • Pre-0.x global-credential migration hint in the startup auth report; falls back to the generic fastagent login hint.

Merge → tag v0.8.3 → GitHub Release; publish.yml re-verifies and publishes to npm via OIDC.

v0.8.2

Choose a tag to compare

@kid7st kid7st released this 04 Jul 15:34

Changed

  • The folder is live: AGENTS.md and skills/ are re-read on every invoke (folder-rung agents: createPiAgentFromDefinition, dev, start). Edits — the author's or the agent's own — take effect on the next turn with no process restart; a broken edit fails that turn visibly instead of the process. createPiAgent (typed parts) is unchanged, and fastagent chat keeps its startup snapshot — restart it to pick up edits.
  • dev watch scope narrowed to code inputs (tools/, channels/, fastagent.config.*, package.json, .env) — the only changes that require a new process (ESM module cache). Files the agent writes into its own workspace no longer kill its in-flight turn with a restart. Helper code imported from outside tools//channels/ is out of watch scope — keep it under tools/, or restart manually.

Full changelog: https://github.com/kid7st/fastagent/blob/main/CHANGELOG.md

v0.8.1

Choose a tag to compare

@kid7st kid7st released this 04 Jul 12:04

Fixed

  • --tunnel no longer mistakes cloudflared's API endpoint for the assigned tunnel URL. Under a flaky network, a cloudflared ERROR line mentioning https://api.trycloudflare.com/tunnel parsed as the tunnel URL and the Telegram webhook got registered against Cloudflare's API host — the bot silently received nothing while every log line said success.
  • Transient provider request failures no longer kill the turn for providers whose pi-ai adapters implement client-side retries (OpenAI-family / Anthropic / Azure / Codex — request-phase network errors / 429 / 5xx with backoff; all previously defaulted to 0 retries). The google / vertex / bedrock / mistral adapters ignore maxRetries, so transients there still fail the turn. Mid-stream drops also still fail the turn — partial output was already streamed and cannot be retracted.

Full changelog: https://github.com/kid7st/fastagent/blob/main/CHANGELOG.md