A standalone Facetwork example package that hosts FFL workflows and handlers wrapping the public surfaces published at github.com/anthropics.
| Area | Status | What it wraps |
|---|---|---|
| Messages API | ✅ 6 facets | CreateMessage, CountTokens, CreateMessageWithTools, CreateMessageWithImages, CreateMessageStream, CreateMessageWithFile (Files-API RAG) |
| Batch API | ✅ 4 facets | SubmitBatch, GetBatchStatus, GetBatchResults, RunBatch (submit + poll + retrieve driver) |
| Files API | ✅ 3 facets | UploadFile, ListFiles, DeleteFile |
| Agent SDK | ✅ 1 facet | RunAgent (Claude Agent SDK) |
| Claude Code | ✅ 1 facet | RunClaudeCode (Claude Code CLI subprocess) |
| Computer Use | ✅ 1 facet | RunComputerUseSession (simulator-backed by default) |
| Cross-area composition | ✅ 1 workflow | anthropic.compose.DocumentQA (Files + Messages RAG) |
All six initial areas are wired (16 facets total). Adding a new area
(mcp, evals, cookbook, …) is purely additive — drop in
handlers/<area>/ + tools/_lib/<area>.py + ffl/<area>.ffl and
wire it into handlers/__init__.py.
Every Anthropic surface is a typed facet, so an LLM call is just another step in a
FFL
workflow — retried, timed out, fanned out and traced like any other. A step is
name = Facet(args); schema results nest (msg.result.text):
namespace my.llm {
use anthropic.files
use anthropic.messages
/** Upload a file, then ask a question against it. */
workflow AskAboutFile(path: String, question: String) => (file_id: String, text: String) andThen {
up = anthropic.files.UploadFile(path = $.path)
msg = anthropic.messages.CreateMessageWithFile(
prompt = $.question,
file_ids = up.result.id,
file_type = "document",
max_tokens = 1024)
yield AskAboutFile(file_id = up.result.id, text = msg.result.text)
}
}
fw ffl run --primary my.ffl \
--library src/anthropic_handlers/ffl/messages.ffl \
--library src/anthropic_handlers/ffl/files.ffl \
--workflow my.llm.AskAboutFile \
--inputs '{"path": "/data/report.pdf", "question": "Headline finding?"}'📖 docs/ffl-examples.md — the full example gallery:
token-budget gating with when, foreach over many prompts, prompt caching, the
Batch API, agent/Claude-Code sessions as steps, and call-time
Timeout/Retry/catch. Every snippet there is compile-checked.
Every integration area has a spec in docs/ — how the call flows
(FFL → handler → tools/_lib → shared SDK client), whether/how it fans out, the schema
fields & JSON-bridge conventions it uses, the libraries/binaries it needs, its
facets & workflows (with Effect/Cost mixins), and its cache/output. Start with the
cross-cutting architecture spec (shared client, the
tools/_lib ↔ handlers ↔ ffl pattern, JSON-bridge fields) and the flagship
Messages API; the full index is in docs/README.md.
| Group | Specs |
|---|---|
| Cross-cutting | architecture |
| Integration areas | messages · batch · files · agent-sdk · claude-code · computer-use |
| Composition | composition |
Discovered by the Facetwork runner via the facetwork.domains entry point
declared in pyproject.toml. After pip install -e ., Facetwork's
fw runner start --domain anthropic and fw ffl seed
pick this package up automatically (even with zero handlers wired today).
git clone https://github.com/rlemke/fwh_anthropic.git ~/fw_handlers/fwh_anthropic
cd ~/fw_handlers/fwh_anthropic
pip install -e .This registers the package under the facetwork.domains entry-point group,
making it discoverable by any Facetwork installation in the same environment.
fw ffl seed --include anthropic
fw runner start --domain anthropic -- --log-format textThe runner reports anthropic: 16 handlers registered [entry_point].
All facets show up in the dashboard's namespace browser.
src/anthropic_handlers/tools/list-areas.shPrints a table of every area subpackage and how many handlers it currently exposes.
The unit suite mocks all SDK calls. To smoke-test against the real Anthropic API:
ANTHROPIC_API_KEY=sk-... pytest tests/live -m live --run-liveSee tests/live/README.md for the full gating contract.
fwh_anthropic/
├── pyproject.toml # facetwork.domains entry point
├── README.md
├── CLAUDE.md # guidance for Claude Code in this repo
├── agent-spec/
│ ├── tools-pattern.agent-spec.yaml # the canonical tools/_lib pattern
│ ├── cache-layout.agent-spec.yaml # cache sidecar protocol
│ └── integration-areas.agent-spec.yaml # how to add a new Anthropic-surface area
├── tests/
└── src/anthropic_handlers/
├── __init__.py # exports `domain: DomainPackage`
├── handlers/
│ ├── __init__.py # register_all_registry_handlers (calls every area)
│ ├── shared/anthropic_utils.py # shim into tools/_lib (auth, retry, rate-limit, …)
│ ├── messages/ # Messages API (6 facets)
│ ├── batch/ # Batch API (4 facets)
│ ├── files/ # Files API (3 facets)
│ ├── agent_sdk/ # Agent SDK (1 facet)
│ ├── claude_code/ # Claude Code CLI (1 facet)
│ └── computer_use/ # Computer Use (1 facet)
├── ffl/ # one .ffl per area + composition.ffl + anthropic.ffl
└── tools/
├── _lib/ # client, auth, rate-limit + one module per area
│ ├── client.py
│ ├── messages.py
│ ├── batch.py
│ ├── files.py
│ ├── agent_sdk.py
│ ├── claude_code.py
│ └── computer_use.py
├── list-areas.sh / .py # inspect wiring status
└── *.py / *.sh # per-facet CLIs (added per area)
| Service | Purpose |
|---|---|
| MongoDB | Facetwork registry + workflow state |
ANTHROPIC_API_KEY |
All Messages / Batch / Files / Agent SDK / Computer Use areas |
The Claude Code area additionally needs claude on PATH; the MCP
area needs the mcp package; the Agent SDK area needs the
claude-agent-sdk package. Install only the optionals you'll use:
pip install -e ".[agent_sdk,mcp]"anthropic.compose.DocumentQA in ffl/composition.ffl is the
canonical RAG pattern: upload a document with anthropic.files.UploadFile,
then ask Claude about it via anthropic.messages.CreateMessageWithFile.
The same pattern applies to any cross-area workflow — keep
event-facet definitions in their per-area .ffl file and put the
multi-step glue in composition.ffl.
- Pick a name that matches the Anthropic surface (e.g.
evals,cookbook,citations). - Add
src/anthropic_handlers/tools/_lib/<area>.pywith pure-function simulators / SDK wrappers. - Add
src/anthropic_handlers/handlers/<area>/__init__.pyexportingregister_handlers(runner)+ a_DISPATCHmap. - Add
src/anthropic_handlers/ffl/<area>.ffldeclaring the namespace + event facets. - Wire it in
src/anthropic_handlers/handlers/__init__.py::register_all_registry_handlers. - Add the area entry to
src/anthropic_handlers/tools/_lib/areas.pysolist-areas.shpicks it up. - (Optional) Re-export key symbols from
handlers/shared/anthropic_utils.py.
See agent-spec/integration-areas.agent-spec.yaml
for the contract a new area should satisfy.
Apache 2.0 — see LICENSE.