Cloudflare released cf, a CLI that mirrors their entire API surface and supports TypeScript configuration-as-code. They also open-sourced Forge, the internal SDK generator that makes it possible. The design philosophy is explicit: build tools that work equally well for humans typing commands and agents executing programmatic workflows.
This is not a curated subset of common operations. It is the full API surface, generated from OpenAPI specs, with type-safe bindings and programmatic configuration. The shift reveals a broader pattern in infrastructure tooling: CLIs are being redesigned with AI agents as first-class users.
What Agentic CLI Actually Means
Traditional CLIs optimize for human discoverability. You type --help, scan flags, and compose commands interactively. Agentic CLIs optimize for programmatic consumption while maintaining human usability.
Key differences:
- TypeScript config-as-code: Instead of parsing flag strings, agents can import the CLI as a library and call functions with typed parameters.
- Full API parity: Every API endpoint has a corresponding CLI command. No need to fall back to raw HTTP when the CLI lacks coverage.
- Generated code: The CLI is not hand-written. It is generated from OpenAPI specs, ensuring it stays in sync with API changes.
Cloudflare's implementation lets you write configuration files in TypeScript that the CLI executes. An agent can generate these files programmatically, version them, and execute them without string interpolation or shell escaping.
// TypeScript config file for cf CLI
import { cf } from '@cloudflare/cf';
export default cf.configure({
zone: {
id: process.env.ZONE_ID,
settings: {
ssl: 'strict',
minify: {
js: true,
css: true,
html: false
}
}
},
workers: {
scripts: [{
name: 'api-gateway',
content: await Deno.readTextFile('./worker.js'),
bindings: {
KV: { namespace_id: process.env.KV_NAMESPACE }
}
}]
}
});
This is executable configuration. The agent does not need to know Cloudflare's flag syntax. It imports the library, calls typed functions, and gets compile-time validation.
Forge: The SDK Generator
Forge is Cloudflare's internal tool for generating SDKs from OpenAPI specs. They open-sourced it alongside the CLI. The workflow:
- OpenAPI spec as source of truth: Cloudflare maintains OpenAPI definitions for their API.
- Code generation: Forge reads the spec and generates TypeScript SDK code with full type coverage.
- CLI wrapping: The CLI is a thin wrapper around the generated SDK, adding command-line parsing and output formatting.
This approach solves the maintenance problem. When Cloudflare adds a new API endpoint, the OpenAPI spec updates, Forge regenerates the SDK, and the CLI automatically supports the new operation. No manual documentation or CLI flag design required.
Trade-offs:
| Aspect | Generated CLI | Hand-Written CLI |
|---|---|---|
| API coverage | Complete, automatic | Curated, manual |
| Maintenance burden | Low (regenerate on spec change) | High (update code, docs, tests) |
| Discoverability | Poor (too many commands) | Good (focused on common tasks) |
| Type safety | Full (generated from spec) | Partial (depends on discipline) |
| Agent usability | Excellent (programmatic API) | Poor (string parsing required) |
| Human usability | Mixed (overwhelming options) | Excellent (guided workflows) |
Cloudflare chose completeness over curation. The CLI has hundreds of commands because the API has hundreds of endpoints. This is a bet that agents will handle the complexity through programmatic interfaces, while humans will use IDE autocomplete and type hints to navigate.
Architecture: CLI as SDK Wrapper
The cf CLI is not a standalone binary that makes HTTP requests. It is a Node.js package that imports the generated SDK and adds a command-line interface layer.
Execution flow:
- Command parsing: The CLI parses command-line arguments into structured data.
- SDK invocation: It calls the corresponding SDK function with typed parameters.
- Response formatting: It formats the SDK response for terminal output (JSON, table, or custom).
For TypeScript config files, the flow is simpler:
- Config loading: The CLI imports the TypeScript file as a module.
- Direct execution: It executes the exported configuration object, which already contains SDK calls.
- Result aggregation: It collects results from all operations and formats output.
This architecture means the CLI and SDK share the same code paths. An agent using the SDK directly gets identical behavior to the CLI, just without the terminal formatting layer.
State Management and Idempotency
Cloudflare's API is RESTful, so state management happens server-side. The CLI does not maintain local state beyond authentication tokens. Each command is a stateless API call.
Idempotency handling:
- Declarative config: TypeScript config files describe desired state, not imperative steps.
- Diff calculation: The CLI can compare current state (fetched via API) with desired state and generate a minimal change set.
- Dry-run mode: Agents can preview changes before applying them.
This is critical for agent workflows. An agent can repeatedly execute the same configuration file without side effects. The CLI calculates what changed and only applies deltas.
// Agent workflow: apply config with diff preview
const config = await generateConfig(requirements);
const diff = await cf.plan(config); // Fetch current state, calculate diff
if (diff.changes.length > 0) {
await cf.apply(config); // Apply only the changes
}
Security Boundaries
The CLI inherits Cloudflare's API security model:
- API tokens: Scoped to specific permissions (read zones, write workers, etc.).
- Token storage: The CLI stores tokens in OS-specific secure storage (Keychain on macOS, Credential Manager on Windows).
-
Environment variables: Tokens can be passed via
CLOUDFLARE_API_TOKENfor CI/CD environments.
For agent workflows, the security boundary is the API token scope. An agent with a read-only token cannot modify infrastructure, even if it has full CLI access. This is better than SSH-based automation, where the agent typically has full shell access.
Risk: TypeScript config execution
TypeScript config files are executable code. If an agent generates a malicious config file, it can execute arbitrary code when the CLI loads it. Mitigation strategies:
- Sandbox execution: Run the CLI in a container with limited filesystem and network access.
- Config validation: Parse the config file statically before execution to detect suspicious patterns.
- Audit logging: Log all config file executions and API calls for forensic analysis.
Observability and Debugging
The CLI supports structured logging and tracing:
- JSON output mode: All commands can output JSON for programmatic parsing.
- Verbose logging: Debug mode shows full HTTP requests and responses.
- Trace IDs: Cloudflare includes trace IDs in API responses, which the CLI surfaces for support requests.
For agent workflows, JSON output mode is essential. The agent can parse responses programmatically without regex scraping terminal output.
# Agent-friendly invocation
cf zones list --output json | jq -r '.[] | select(.name == "example.com") | .id'
Deployment Shape
The CLI is distributed as an npm package. This is unusual for infrastructure CLIs, which typically ship as standalone binaries (Terraform, kubectl, etc.). The npm distribution model has implications:
Advantages:
-
Easy integration: Agents can
npm install @cloudflare/cfand import it directly. - Version pinning: Lock files ensure reproducible builds.
- Dependency management: npm handles transitive dependencies automatically.
Disadvantages:
- Node.js requirement: You need a Node.js runtime, which adds weight to container images.
- Supply chain risk: npm dependencies introduce additional attack surface.
- Startup latency: Node.js startup is slower than native binaries.
For agent harnesses, the npm distribution is a net positive. Most agent runtimes already include Node.js, and the ability to import the CLI as a library outweighs the startup cost.
Failure Modes
1. API spec drift
If Cloudflare's OpenAPI spec diverges from actual API behavior, the generated CLI will have bugs. This is a risk with any code generation approach. Mitigation: comprehensive integration tests that run against production API.
2. Rate limiting
Agents executing many CLI commands in parallel can hit Cloudflare's rate limits. The CLI does not implement automatic retry with backoff. Agents must handle this at the orchestration layer.
3. TypeScript config errors
Syntax errors in config files cause runtime failures. The CLI does not pre-validate configs before execution. Agents should lint generated configs before passing them to the CLI.
4. Token expiration
API tokens can expire or be revoked. The CLI does not refresh tokens automatically. Agents must implement token rotation logic.
When to Use This Pattern
Good fit:
- You have a large API surface (hundreds of endpoints) that changes frequently.
- You want agents to interact with your infrastructure programmatically.
- You already maintain OpenAPI specs for your API.
- Your users are comfortable with TypeScript or JavaScript.
Poor fit:
- You have a small, stable API where hand-written CLI commands provide better UX.
- Your users expect a standalone binary with no runtime dependencies.
- You need sub-second CLI startup time (Node.js startup is ~100ms).
- Your API does not have OpenAPI specs and you do not want to maintain them.
The Cloudflare approach works because they already had comprehensive OpenAPI specs and a large API surface. For smaller projects, the overhead of maintaining specs and running a code generator may not be worth it.
Technical Verdict
Use Cloudflare's cf CLI when:
- You are building agent workflows that need full Cloudflare API coverage.
- You want type-safe, programmatic configuration instead of shell scripting.
- You can tolerate Node.js as a runtime dependency.
Avoid it when:
- You need a curated CLI with guided workflows for human operators.
- You are deploying in environments without Node.js (embedded systems, minimal containers).
- You need sub-100ms CLI startup time for tight loops.
Use the Forge pattern (generated CLI from OpenAPI) when:
- You maintain a large API surface that changes frequently.
- You want to support multiple SDKs (TypeScript, Python, Go) from a single source of truth.
- You can invest in comprehensive integration testing to catch spec drift.
Avoid Forge when:
- Your API is small and stable enough to hand-write SDKs.
- You need fine-grained control over SDK ergonomics that code generation cannot provide.
- You do not have resources to maintain OpenAPI specs alongside your API.
The agentic CLI pattern is emerging across infrastructure tooling. Cloudflare's implementation shows the plumbing: OpenAPI as source of truth, code generation for SDK coverage, TypeScript for executable configuration, and npm distribution for programmatic access. The trade-off is clear: you sacrifice human discoverability for agent usability. Whether that trade-off makes sense depends on who your primary user is.
Top comments (1)
A CLI with hundreds of commands is unusable for humans but ideal for agents that never browse, and that completeness-over-curation trade-off is the crux of the whole piece. The security section is the part most agentic-CLI writeups skip. TypeScript config as executable code is a real risk. Do you think the Forge pattern works for teams that don't already have comprehensive OpenAPI specs, or is the spec maintenance the actual prerequisite?