Help us shape the future of Go! Take the 2026 Go Developer Survey

fiber

module
v0.18.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Oct 20, 2026 License: Apache-2.0

README

fiber

Define agents, run them durably, and stream answers across your tools.

Download · Report Bug · Go Docs

Release   CI   Go Reference   License

Real output from the offline example. The model and destination services are simulated.

Status

fiber is v0 alpha software. It is pre-1.0 and not recommended for production.

Interfaces are still moving and may change between minor versions, and a minor release may require code changes on your side.

What that means concretely today:

  • Works and is tested. The single-binary deployment (in-memory bus, ledger and registry), the topic and delivery model, durable runs with replay, the Connect and SSE transports, and the Slack, GitHub, Jira, cron and webhook connectors.
  • New and lightly exercised. Postgres persistence for agent specs, runs and knowledge (FIBER_POSTGRES_URL), the knowledge layer, the built-in author agent, and history compaction. The Postgres backends pass the same suites as their in-memory counterparts in CI's integration job and in make e2e; none of it has seen production load.

See Limitations for the full list.

fiber is an agent platform and a low-latency pub/sub bus. Define an agent with a spec, tag it from Slack, GitHub, Jira or a schedule, and its events stream to any subscriber while being delivered to any destination you name.

Where a tag is raised and where its answer lands are independent. A GitHub request can stream into Slack while a webhook receives only its completion event. Each run pins an agent revision, so retries use the same definition.

Features

  • Agents are documents. Create one by submitting a spec. No redeploy, no code, no restart.
  • Subscribe once. agent:docs-bot receives current and future runs of that agent through one topic.
  • Route by event. Send one run to multiple destinations; each chooses text, citations, lifecycle events, or all of them.
  • Connectors act, not just talk. The Actor face contributes native verbs (transition a Jira ticket, request a review) as agent tools, sandboxed by NGAC, each emitting an auditable action.taken event.
  • Persistent when configured. Postgres keeps definitions, runs, and knowledge across restarts; Redis carries the event stream. In-memory backends keep local development simple.
  • Revisions are pinned per run. A run accepted under revision 6 executes as revision 6 forever, even after a revise, because replay demands it.
  • Citations are first-class events, carrying the exact quoted source and resolvable provenance.
  • Every run reports what it spent. Each model call is a usage.call event (tokens, cache share, model, context window, and cost where saige's price catalog has the model), and the run's total, delegations included and each call counted once, is on its terminal event and GetRun.
  • A run can wait for a person. A tool listed in a spec's approvals, or the built-in ask_person tool, parks the run on a question (approve or deny a call, pick an option, or reply). The run frees its worker, survives restarts, publishes the question on lifecycle.parked, and resumes with the first answer (InvokeService.Answer, fiber answer). An unanswered question takes its default when it expires.
  • One contract, three transports. Connect serves gRPC, gRPC-Web and HTTP/JSON, plus resumable SSE for browsers.

Installation

Prerequisites

Path Requirements
Prebuilt CLI macOS or Linux
Build or run examples Go version from go.mod, Git
Persistent local stack Docker with Compose v2, Make
Real model inference Provider credentials, a local Ollama service, or an OpenAI-compatible server

Script (macOS / Linux)

curl -fsSL https://raw.githubusercontent.com/urmzd/fiber/main/install.sh | sh

Go

go install github.com/urmzd/fiber/cmd/fiber@latest

Library

go get github.com/urmzd/fiber

Quick Start

Run the complete offline example from a checkout. After Go downloads its dependencies, the demo needs no API key or external services:

git clone https://github.com/urmzd/fiber.git
cd fiber
go run ./examples/local

It creates an agent, revises it, tags it from a simulated GitHub trigger with delivery routed to Slack and a webhook, shows a third party listening to the agent's topic, and demonstrates that a replayed run does not pay for the model twice.

Persistent local stack

From the same checkout:

make up
make e2e

Compose starts Postgres, Redis, and fiber at http://localhost:8383. The end-to-end check creates and revises an offline agent, runs it, restarts fiber, checks persistence, and verifies a citation from indexed documentation. It does not call a paid model. Run make down to stop the stack and keep its data.

Use a model

With the CLI installed, run the server in one terminal:

export ANTHROPIC_API_KEY="your-api-key"
export FIBER_TOKEN="local-development-token"
fiber serve

In another terminal, use the same token and a model your provider account supports:

export FIBER_TOKEN="local-development-token"

cat > docs-bot.json <<'JSON'
{
  "name": "docs-bot",
  "description": "Answers questions about the deploy pipeline",
  "provider": "anthropic",
  "model": "claude-haiku-5-5",
  "system_prompt": "You answer questions about the deploy pipeline. Cite your sources."
}
JSON

fiber agent create -f docs-bot.json
fiber tag docs-bot "how does a release get out the door?"

To use OpenAI, or any server that speaks its Chat Completions API (vLLM, LM Studio, llama.cpp, OpenRouter, Groq), set "provider": "openai" and the model that server hosts. For a local server, point fiber at it instead of setting a key:

export OPENAI_BASE_URL="http://localhost:8000/v1"   # omit for OpenAI itself
export OPENAI_API_KEY="your-api-key"                # optional for a local server

Models saige's catalog does not know report their token usage and no cost.

An agent can name fallback models, tried in order when a call to its primary model fails with an error another model could fix (an outage, a rate limit, a refused credential):

"fallbacks": [
  {"provider": "openai", "model": "gpt-5"},
  {"provider": "ollama", "model": "llama4"}
]

Each fallback names a provider the deployment knows and a model, none repeats the primary or another fallback, and there are at most four. By default any error another model could fix falls through. "fallback_on" narrows that to named classes: unavailable (an outage), rate_limit, transient (a timeout or reset connection, and also a rate limit or outage), auth, context_length and content_filter, or any alone, which is the default. For example "fallback_on": ["rate_limit", "unavailable"]. It is a set, and naming it without fallbacks is refused. Whatever it names, an invalid request, a stopped run or an exhausted budget does not fall through, and a stream that already produced output is not replayed on another model. Every fallback is built with the agent, so one whose provider is not configured (say, OPENAI_API_KEY is unset) fails the build like the primary would. Each call is priced on the rate card of the model that answered it. Order is part of the revision: reordering fallbacks is an edit. A spec without fallbacks hashes exactly as it did before they existed.

An agent can be granted an MCP provider's tools as one name: "tools": ["mcp:urmzd"] grants every tool an admin accepted on the provider urmzd. The model is shown each member tool (urmzd__create_issue), never the group, and approvals name members: "approvals": ["urmzd__create_issue"]. The group is expanded each time a run builds the agent, so a newly accepted tool reaches the agent without a new revision. fiber serve does not connect to MCP servers yet; a host embedding pkg/agentrt supplies groups with agentrt.WithToolGroups or from its tool catalog.

After configuring the GitHub and webhook connectors, route the same agent's answer to multiple destinations. Replace the example addresses with yours:

fiber tag docs-bot "how does a release get out the door?" \
  --deliver 'github://urmzd/fiber/issues/42|delta' \
  --deliver 'webhook://acme/deploys|lifecycle.completed'

Watch the bus. This subscriber invoked nothing and still sees every run:

fiber listen agent:docs-bot
fiber listen agent --kinds lifecycle.completed --format json | jq

Examples

Example What it demonstrates
local Offline agent revisions, selective delivery, citations, and replay
compose Postgres persistence, Redis streaming, and indexed documentation

See the example index for more.

Commands

Command Purpose
fiber serve Run the core: API, SSE, webhooks, bus, router, worker
fiber work Run an execution node with no inbound API
fiber agent Create, revise, get, list, history, delete
fiber tag Tag an agent and stream its answer
fiber listen Subscribe to a topic and print events
fiber stop Ask a run to stop; it keeps what it had said and ends with lifecycle.stopped
fiber answer Answer the question a parked run is waiting on (--approve, --deny, --choose, --reply)
fiber index Index files into a named knowledge source in Postgres
fiber version Version, commit, build date
fiber update Self-update from GitHub releases

Every command takes --format text|json. Results go to stdout, diagnostics to stderr, so --format json output pipes cleanly into jq even while the same process logs a reconnect.

Documentation

Document Covers
docs/architecture/overview.md Topics, connector faces, N:M delivery, revision pinning, package DAG, limitations
AGENTS.md AI-facing conventions, commands, rules, extension guide
examples/README.md Runnable example index
CONTRIBUTING.md Development workflow and commit convention
SECURITY.md Security boundaries and reporting

API reference: pkg.go.dev/github.com/urmzd/fiber

Architecture

fiber builds on three libraries and adds addressing, distribution and the control plane:

Concern Owner
Agent loop, typed deltas, RAG, citations saige
Durability, replay, per-run journal anchor
Sandboxed execution nodes, NGAC playscape
Topics, bus, routing, connectors, specs fiber

See the architecture guide for delivery, authorization, and replay guarantees. warp adds product workflows and a web surface on top of the platform.

Configuration

Variable Purpose
FIBER_TOKEN Shared development credential for the server and CLI
FIBER_TENANT Authorization scope; defaults to default
FIBER_POSTGRES_URL Persist the registry, run ledger, queue, and knowledge
FIBER_REDIS_URL Use Redis Streams for the event bus
ANTHROPIC_API_KEY Authenticate the Anthropic provider
OPENAI_API_KEY Authenticate the openai provider; optional with OPENAI_BASE_URL
OPENAI_BASE_URL Point the openai provider at an OpenAI-compatible server
FIBER_EMBEDDINGS_URL, _MODEL, _KEY, _DIMENSIONS Configure an OpenAI-compatible embeddings endpoint
FIBER_AUTHOR_PROVIDER, FIBER_AUTHOR_MODEL Select the built-in author agent's model
FIBER_COMPACT_TOKENS Enable history compaction at a token threshold; off by default
FIBER_COMPACT_KEEP_TURNS Recent tool-calling turns a compaction keeps verbatim; defaults to saige's
FIBER_COMPACT_ON_REQUEST Let a host compact a running turn with POST /v1/runs/{id}/compact; off by default

Without an embeddings endpoint, indexing uses a local hashing embedder for offline development. Use the same embedding settings for serve and index.

Compose sets FIBER_TOKEN=fiber-dev-token by default. Use that value when connecting from a host CLI. Connector setup is covered in the GitHub and Slack guides.

Upgrading

Run ids changed in this release. A run id is now derived from the tenant and the tag id together, so every run gets a different id than it had before.

  • Drain before upgrading. Stop accepting tags and let in-flight runs finish on the old version. A durable replay recomputes the run id from the tag, so a run accepted by the old version and resumed by the new one is looked up under an id it was never stored under. Do not run old and new workers against the same ledger.
  • Old redeliveries start new runs. A webhook redelivered across the upgrade no longer deduplicates against the run its first delivery created, because that run is stored under its old id.
  • Upgrade clients for the stopped status. GetRun can now report RUN_STATUS_STOPPED (6) for a run that was asked to stop. A client generated before this release decodes it as an unknown enum value, so a poller waiting for completed or failed never sees a stopped run end. Regenerate or upgrade clients; until then, treat an unknown status as terminal or watch for lifecycle.stopped on the run's stream.
  • Stored run ids are stale. Anything that saved a run id from before the upgrade (a link, a dashboard, a surface message) will not resolve it afterwards.

Limitations

  • Event streaming uses the in-memory bus or Redis independently of the Postgres run store.
  • The registry, run ledger and run queue are in memory unless FIBER_POSTGRES_URL is set. On Postgres they survive a restart, but anchor's pgqueue has no DeltaLog, so the per-run journal is not written; the bus still carries every event.
  • playscape's queue is at-most-once in beta, so durability comes from anchor rather than from playscape.
  • Citations are derived from RAG context blocks. saige's CitationDelta, which reports what a model or tool cited, is not translated into events yet.
  • The bus is at-least-once with no consumer groups. If durable competing consumers become a requirement, NATS JetStream behind the Bus interface is a better answer than growing a broker here.
  • Agent specs load from JSON, not YAML.
  • Stopping a run is the HTTP route POST /v1/runs/{id}/stop, not an RPC; GetRun reports the result as RUN_STATUS_STOPPED. A stop is recorded in the run ledger before it is announced on the bus, so once it is acknowledged the run ends stopped unless its turn had already returned its answer. A route that selects only lifecycle.completed is not told about a stop.
  • Compacting a running turn on request is the HTTP route POST /v1/runs/{id}/compact, not an RPC. The request is not recorded: it reaches only the attempt running when it is made, before that turn's next model call. See Compacting a run on request.
  • A granted tool this deployment cannot resolve (no connector contributes it, or an MCP tool is held back) is dropped rather than failing the run. The model is told it is unavailable and the server logs a warning naming the tool and the reason; agentrt.WithStrictTools restores the old refusal.
  • Tool events carry the call's arguments, capped at 8 KiB; scrub sensitive ones with agentrt.WithToolArguments.
  • A parked run waits on a person through the run ledger. An answer or a stop wakes it at once; an expired question is noticed by the worker's janitor poll (30 seconds by default), so its default applies up to that late. The requester cannot approve their own calls unless the spec sets self_approval, and approvers/answerers restrict who may answer. A tool implementing agentrt.Approving decides per call whether it needs approval and may name that call's approvers, which then replace the spec's. A host Delegator that blocks on a child run holds a worker and can exhaust them; runtime.WithChildRuns parks the parent on the child instead. Approvals inside an in-turn sub-task (a tag_<agent> call without child runs or a Delegator) are refused, not asked. See Parking a run on a person.
  • Cost is reported only for models saige's price catalog prices, in integer micro-units with the catalog's as_of; anything else reports tokens and no cost. Usage is delivered only to routes that select usage. A turn that crashes mid-call is on the bus but not in the run's total. In-turn delegation is one level deep (a sub-task holds no spawn grant), and a host that runs delegations as runs of their own rolls them up with runtime.ReportChildUsage. See Usage.

Reproduce the Screenshot

Install teasr, then run from this checkout:

go run ./examples/local
teasr run --config teasr.toml

The first run warms Go's build cache. The capture runs the real demo and writes showcase/durable-replay.png.

License

Apache 2.0. See LICENSE.

Directories

Path Synopsis
cmd
fiber command
Command fiber is the agent platform and its pub/sub bus.
Command fiber is the agent platform and its pub/sub bus.
examples
local command
Command local is fiber, end to end, in one process.
Command local is fiber, end to end, in one process.
gen
internal
cli
Package cli is the fiber command tree and the process's composition root.
Package cli is the fiber command tree and the process's composition root.
server
Package server is fiber's transport edge.
Package server is fiber's transport edge.
pkg
address
Package address is the naming layer of the mesh: a stable URI for any place a tag can come from or be delivered to.
Package address is the naming layer of the mesh: a stable URI for any place a tag can come from or be delivered to.
agentrt
Package agentrt builds a running agent from a pinned agent revision.
Package agentrt builds a running agent from a pinned agent revision.
agentrt/payload
Package payload is the body of every event an agent run publishes.
Package payload is the body of every event an agent run publishes.
agentspec
Package agentspec is the canonical definition of an agent, and the rules that decide when two definitions are the same one.
Package agentspec is the canonical definition of an agent, and the rules that decide when two definitions are the same one.
attachment
Package attachment is the typed reference to a file an agent was handed.
Package attachment is the typed reference to a file an agent was handed.
attachment/intake
Package intake is how a file's bytes get into the blob store and come out as an attachment.Attachment.
Package intake is how a file's bytes get into the blob store and come out as an attachment.Attachment.
attachment/resolve
Package resolve turns attachment references into model input.
Package resolve turns attachment references into model input.
attachment/resolve/resolvetest
Package resolvetest provides deterministic stand-ins for the backends pkg/attachment/resolve only defines interfaces for: a Transcriber, a FrameSampler and a Prober.
Package resolvetest provides deterministic stand-ins for the backends pkg/attachment/resolve only defines interfaces for: a Transcriber, a FrameSampler and a Prober.
blob
Package blob is a content-addressed store for the bytes of files an agent is handed: a screenshot pasted into a Slack thread, a log attached to a GitHub issue, a PDF on a Jira ticket.
Package blob is a content-addressed store for the bytes of files an agent is handed: a screenshot pasted into a Slack thread, a log attached to a GitHub issue, a PDF on a Jira ticket.
blob/blobtest
Package blobtest is the conformance suite every blob store must pass.
Package blobtest is the conformance suite every blob store must pass.
bus
Package bus is the broker: a run publishes its events once, and every consumer that asked for them receives them.
Package bus is the broker: a run publishes its events once, and every consumer that asked for them receives them.
bus/bustest
Package bustest is the conformance suite every bus backend must pass.
Package bustest is the conformance suite every bus backend must pass.
connector
Package connector defines what it means to participate in the mesh.
Package connector defines what it means to participate in the mesh.
connectors
Package connectors holds the mesh: the concrete peers that raise tags and render events onto real surfaces.
Package connectors holds the mesh: the concrete peers that raise tags and render events onto real surfaces.
connectors/author
Package author turns the agent control plane into tools an agent can call.
Package author turns the agent control plane into tools an agent can call.
connectors/cron
Package cron is the schedule peer in the mesh: a trigger, and only a trigger.
Package cron is the schedule peer in the mesh: a trigger, and only a trigger.
connectors/github
Package github is the GitHub peer in the mesh: trigger, sink and actor.
Package github is the GitHub peer in the mesh: trigger, sink and actor.
connectors/internal/files
Package files is the part of file intake every trigger shares: collecting a message's files onto its tag under the per-tag caps, logging what was left out, and handing the tag off without discarding work the provider stopped waiting for.
Package files is the part of file intake every trigger shares: collecting a message's files onto its tag under the per-tag caps, logging what was left out, and handing the tag off without discarding work the provider stopped waiting for.
connectors/internal/httpjson
Package httpjson is the JSON-over-HTTP client the connectors' real API implementations share.
Package httpjson is the JSON-over-HTTP client the connectors' real API implementations share.
connectors/internal/inbound
Package inbound is the front door every webhook trigger shares: authenticate the request, then hand the raw bytes to whoever knows how to read them.
Package inbound is the front door every webhook trigger shares: authenticate the request, then hand the raw bytes to whoever knows how to read them.
connectors/internal/render
Package render accumulates one run's event stream into a document a sink can draw, repeatedly, without ever drawing something stale.
Package render accumulates one run's event stream into a document a sink can draw, repeatedly, without ever drawing something stale.
connectors/internal/sink
Package sink is the delivery engine every human-facing connector shares: one message per run, edited as the run proceeds.
Package sink is the delivery engine every human-facing connector shares: one message per run, edited as the run proceeds.
connectors/jira
Package jira is the Jira peer in the mesh: trigger, sink and actor.
Package jira is the Jira peer in the mesh: trigger, sink and actor.
connectors/mention
Package mention finds the agent a human tagged and removes the mention from the text the agent will read.
Package mention finds the agent a human tagged and removes the mention from the text the agent will read.
connectors/slack
Package slack is the Slack peer in the mesh: trigger, sink and actor.
Package slack is the Slack peer in the mesh: trigger, sink and actor.
connectors/webhook
Package webhook is the outbound peer in the mesh: a sink, and only a sink.
Package webhook is the outbound peer in the mesh: a sink, and only a sink.
durable
Package durable owns the Postgres schema that anchor's run ledger and queue are stored in, so a run in flight outlives the process that accepted it.
Package durable owns the Postgres schema that anchor's run ledger and queue are stored in, so a run in flight outlives the process that accepted it.
envelope
Package envelope is the contract every fiber client speaks, independent of transport.
Package envelope is the contract every fiber client speaks, independent of transport.
knowledge
Package knowledge is the retrieval layer: it indexes documents and answers a query with the passages most likely to contain the answer, each one carrying enough provenance to be cited.
Package knowledge is the retrieval layer: it indexes documents and answers a query with the passages most likely to contain the answer, each one carrying enough provenance to be cited.
mcptools
Package mcptools connects to the MCP servers pkg/toolprovider records and turns the tools an admin accepted into callables an agent can use.
Package mcptools connects to the MCP servers pkg/toolprovider records and turns the tools an admin accepted into callables an agent can use.
registry
Package registry is the agent control plane: the append-only record of what every agent has ever been, scoped by tenant.
Package registry is the agent control plane: the append-only record of what every agent has ever been, scoped by tenant.
router
Package router is the delivery half of the mesh: it turns "the agent said something" into "the surface shows it".
Package router is the delivery half of the mesh: it turns "the agent said something" into "the surface shows it".
runtime
Package runtime is the durable turn: where a tag becomes a run.
Package runtime is the durable turn: where a tag becomes a run.
signature
Package signature authenticates inbound webhook requests.
Package signature authenticates inbound webhook requests.
thread
Package thread is the memory of a conversation: an append-only journal of what was said in one thread, kept so that the next run in that thread can be shown it.
Package thread is the memory of a conversation: an append-only journal of what was said in one thread, kept so that the next run in that thread can be shown it.
thread/threadtest
Package threadtest is a surface for tests: a thread.Lister that holds messages in memory and lets a test do to them what people do on a real surface, which is post, edit and delete.
Package threadtest is a surface for tests: a thread.Lister that holds messages in memory and lets a test do to them what people do on a real surface, which is post, edit and delete.
toolprovider
Package toolprovider is the control plane for external tool servers: the record of which MCP servers a tenant may reach, and the versioned list of tools an admin has accepted from each.
Package toolprovider is the control plane for external tool servers: the record of which MCP servers a tenant may reach, and the versioned list of tools an admin has accepted from each.
topic
Package topic is the addressing scheme of the fiber bus.
Package topic is the addressing scheme of the fiber bus.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL