<!--
  GENERATED FILE — do not edit.

  Change tools/generate-guides.ts or its typed sources, run `bun run guides`,
  and commit the generator and rendered files together.
-->

# Compute Agent and CLI

The node agent deploys on a compute; tenant mode holds only its authorized Deployment bindings across environments in RAM and serves them over a group-scoped unix socket, while platform mode never duplicates the API vault.

## Install

Operator CLI and managed-node agent for bootstrap, deploy and lifecycle. Every managed compute. It owns node identity, attestation and repository pipelines. An SNP compute may cache only the exact Deployment binding aliases requested by an authorized local application after current attestation. Ordinary compute is API-only unless an administrator explicitly records the versioned non-TEE risk acceptance for that concrete machine. Platform mode never replicates realm-wide API authority beside the process that already holds unlocked realm seeds.

```text
bun add -g @forgezero/agent
```

<a id="agent-typed-deploy"></a>
## Author a typed, placed containerd deployment

TypeScript is authoring only. The checked-in canonical plan is what Agents validate and execute. Targets declare bounded resource/cardinality intent, not hostnames. The API reserves eligible Realm capacity or provisions only under the reviewed plan and spend ceiling, assigns stable slots, and the Agent runs only its exact assignment. An optional per-metal topology elects one active relay and one standby without naming computes: one or two Metals use proven private relay links and never install WARP, while three or more give Mesh/WARP authority only to relay and standby. runc containers must declare hard CPU, memory and PID limits, bounded storage, loopback ingress and a health-gated rollout; select Kata QEMU SNP when the workload needs host isolation.

```text
import {
  actions,
	  application,
	  credential,
	  defineDeployment,
	  input,
	  providers,
	  ref,
  stage,
  target,
  workflow,
} from '@forgezero/agent/deploy';

export default defineDeployment({
  apiVersion: 'deploy.forgezero.net/v2', kind: 'Deployment',
  metadata: { name: 'orders-api' },
  spec: {
    source: { branch: 'main' },
	inputs: {
	  replicas: input.integer({ minimum: 1, maximum: 16, default: 1 }),
	  cpuCores: input.integer({ minimum: 1, maximum: 32, default: 1 }),
	  memoryMiB: input.integer({ minimum: 256, maximum: 131072, default: 512 }),
	  storageGiB: input.integer({ minimum: 4, maximum: 2048, default: 8 })
	},
	credentials: {
	  cloudflare: credential.infrastructure({ schema: 'forgezero.cloudflare/management@1', name: 'cloudflare-management' })
	},
	targets: { api: target.compute({
	  profiles: ['api'], replicas: { minimum: 1, desired: input.ref('replicas'), maximum: 16 },
	  resources: { cpuCores: input.ref('cpuCores'), memoryMiB: input.ref('memoryMiB'), storageGiB: input.ref('storageGiB') },
	  os: 'ubuntu-24.04', runtime: 'oci-runc', sharing: 'shared', reuse: 'prefer',
	  provisioning: {
	    regionKey: 'default', imageKey: 'ubuntu-24.04-x64', environmentKey: 'production', ownership: 'platform',
	    resources: {
	      physicalCores: 1, vcpu: 2, memoryGib: 2, diskGib: 16, diskEncryption: 'luks2',
	      egressGuaranteedMbps: 100, egressBurstMbps: 200, confidential: false
	    },
	    monthlyAmountCents: '1200', maxMonthlySpendMinor: '25000'
	  },
	  connectivity: {
	    private: { mode: 'private-lan' },
	    public: { mode: 'cloudflare-tunnel', credential: 'cloudflare', zone: 'example.com', hostname: { mode: 'indexed', prefix: 'api' } }
	  },
	  topology: {
	    groupBy: 'metal',
	    relays: {
	      activePerMetal: 1,
	      standbyPerMetal: 1,
	      healthPort: 3000,
	      routedTcpPorts: [3000]
	    },
	    crossMetal: {
	      mode: 'auto',
	      directPrivateMaximumMetals: 2,
	      credential: 'cloudflare',
	      network: 'orders-api'
	    }
	  },
	  placement: { spreadBy: ['metal'], antiAffinity: ['orders-api'] }
	}) },
	requirements: {
	  containerd: providers.containerd.require(), nginx: providers.nginx.require(),
	  cloudflared: providers.cloudflared.require()
	},
    components: {
      api: application({
        target: 'api',
		runtime: { kind: 'container', provider: 'forgezero.containerd', requirement: 'containerd', runtimeClass: 'runc', image: { source: { kind: 'build', context: '.', dockerfile: 'Dockerfile' } }, security: { privileged: false, noNewPrivileges: true, root: 'read-only', dropCapabilities: ['ALL'] } },
        service: { protocol: 'http', port: 3000, health: { protocol: 'http', method: 'GET', path: '/health', expectedStatus: [200], timeoutMs: 2000 } },
		state: { mode: 'stateless' },
		resources: { cpu: { limit: 1 }, memory: { limitMiB: 512, swap: 'disabled' }, pids: { limit: 256 } },
        storage: [{ class: 'ephemeral', path: '/tmp', type: 'tmpfs', sizeMiB: 128 }],
	        network: {
	          ingress: { exposure: 'public', stablePort: 3000 },
	          public: { mode: 'cloudflare-tunnel' },
	          container: { mode: 'bridge', network: 'api' }
	        },
		rollout: { strategy: 'blue-green', proxy: 'nginx', drain: { mode: 'timeout', timeoutMs: 30000 }, automaticRollback: true }
      })
    },
	workflows: { deploy: workflow({ stages: {
	  prepare: stage({ strategy: { mode: 'sequential' }, steps: {
		    software: actions.software.ensure({ requirements: ['containerd', 'nginx', 'cloudflared'] }, { scope: { kind: 'each-target', target: 'api' } }),
		    network: actions.network.ensure({ target: 'api' }, { scope: { kind: 'each-target', target: 'api' } }),
		    image: actions.container.build({ component: 'api' }, { scope: { kind: 'each-target', target: 'api' } })
	  } }),
	  release: stage({ dependsOn: ['prepare'], strategy: { mode: 'blue-green' }, steps: {
	    promote: actions.service.promote({ component: 'api', imageDigest: ref.stepOutput('image', 'digest') }, { scope: { kind: 'each-target', target: 'api' } })
	  } })
	} }) }
  }
});
```

## Choose an entry point

Import the capability your application needs. Each package ships TypeScript declarations. Backend-only entries must stay out of browser bundles.

| Import or command | Use it for | Runtime |
|---|---|---|
| @forgezero/agent/deploy | Typed deployment authoring builders, built-in provider requirements and versioned action constructors. | Bun / Node |

## Work with current access

The live route matrix is the only route authority. Sign in with fz login, then use only your authorized Deployment bindings. The Agent keeps identity and attestation separate from the application socket.

## Related packages

Add only the packages needed by your application.

| Package | Purpose | Guide |
|---|---|---|
| @forgezero/vault | Exact Deployment binding reads through a managed Agent or signed API credential. | [Read guide](/docs/vault-package) |
| @forgezero/access | Typed route, principal, factor, RBAC and request-pipeline contracts. | [Read guide](/docs/access) |
| @forgezero/providers | Typed external providers with priority, health and classified fallback. | [Read guide](/docs/providers) |
| @forgezero/runtime | Portable runtime primitives for queries, jobs, events, schemas and finance. | [Read guide](/docs/runtime) |

Full rendered documentation: https://www.forgezero.net/docs/agent
