# Forgium Agent public integration documentation — full source pack Manifest version: 12 Contract version: 2.1.0 --- BEGIN docs/integration/use-with-an-agent.md --- # Use Forgium Agent with an agent This is the single public entrypoint for a coding agent integrating a host application with Forgium Agent. The public documentation is the canonical contract. The optional Skill is not currently distributed as an installable package; use this protocol unless your runtime already supports a verified local `SKILL.md`. ## Machine-readable discovery An agent can discover the complete public contract without guessing URLs: - [Agent manifest](/agent-manifest.json) — canonical resources, versions, routes, required environment variables, and stop conditions. - [Agent index](/agent-index.json) — generated resource index and hashes. - [LLM index](/llms.txt) — concise reading order and route summary. - [Raw OpenAPI contract](api.openapi.yaml) — exact public request and response schemas. - [Contract retrieval](contract-retrieval.md) — direct download, validation, and blocker reporting when an agent cannot locate the contract. - [HTTP integration reference](reference-implementation.md) — server-side adapter pattern and production checklist. The same resources are available from the public site at: ```text https://docs.forgium.dev/agent-manifest.json https://docs.forgium.dev/agent-index.json https://docs.forgium.dev/llms.txt https://docs.forgium.dev/docs/integration/api.openapi.yaml ``` Use only links published by the manifest or this page. Do not guess or enumerate undocumented `openapi.json`, `swagger.json`, or API paths. ## Decision protocol 1. Read the [agent manifest](/agent-manifest.json), this page, the [Overview](overview.md), and [Environments](environments.md). 2. Determine the goal: - **Connectivity test only:** do not inspect or modify an unrelated repository; use [Getting started](getting-started.md) to send the first HTTP message. - **Code integration:** identify the host application's repository and where the integration belongs. Before running repository commands, confirm the working directory with `pwd` and change to the host repository explicitly. Do not assume a data source, tunnel, framework, or deployment model. 3. For a code integration, choose the smallest applicable route: - **HTTP:** the host application needs a synchronous agent response. - **Capabilities:** the agent needs approved live data or actions from the host application. Capabilities may coexist with HTTP, but are not required for a basic message integration. 4. When a real API call is needed, confirm the target environment's `FORGIUM_AGENT_BASE_URL` and `FORGIUM_AGENT_API_KEY`. If either is missing, [request access](request-access.md); continue only with local work or mocks, and do not claim an end-to-end result. 5. Read the [OpenAPI contract](api.openapi.yaml) and, if discovery fails, follow [Contract retrieval](contract-retrieval.md) before writing calls. For an HTTP code integration, use the [HTTP integration reference](reference-implementation.md) as a pattern only; implement only what the repository needs. 6. Run the applicable local or authenticated smoke test. For a code integration, also run the host repository's tests. For capabilities, follow the complete lifecycle in [Self-service business capabilities](capability-handoff.md). 7. Report what changed, the evidence that passed, and every concrete blocker with its next action. Do not collapse multiple blockers into an artificial single blocker. ## Stop conditions Stop the integration and report the blocker instead of guessing or probing when: - the canonical OpenAPI contract or selected route guide cannot be reached through the published links; use [Contract retrieval](contract-retrieval.md) once, then report the exact HTTP status and content type instead of probing; - `FORGIUM_AGENT_BASE_URL` or `FORGIUM_AGENT_API_KEY` is missing for a real API call; - the access bundle does not identify the requested environment; - the endpoint URL, credential, or capability manifest is a placeholder, unauthenticated, or belongs to another environment; or - a contract test, activation, or final chat verification fails. A missing Git repository is not by itself an integration failure. Only run Git commands when the host repository uses Git or when version-control evidence was specifically requested. ## Route reference | Goal | Read first | Completion evidence | |---|---|---| | Connectivity | [HTTP quickstart](getting-started.md) | First HTTP message returns an assistant response | | HTTP code integration | [Overview](overview.md), [HTTP reference](reference-implementation.md), and [OpenAPI](api.openapi.yaml) | Host tests plus authenticated smoke test | | Host data or actions | [Capabilities lifecycle](capability-handoff.md) | Import, contract test, activation, and chat verification | ## Copy this prompt ```text You are integrating my application with Forgium Agent. Use only the official public integration documentation at https://docs.forgium.dev/docs. Start with these canonical resources; do not guess or enumerate undocumented URLs: 1. https://docs.forgium.dev/agent-manifest.json 2. https://docs.forgium.dev/docs/integration/use-with-an-agent 3. https://docs.forgium.dev/docs/integration/overview 4. https://docs.forgium.dev/docs/integration/environments 5. https://docs.forgium.dev/docs/integration/api.openapi.yaml Use the manifest's published links for the selected route: - HTTP quickstart: https://docs.forgium.dev/docs/integration/getting-started - Capabilities lifecycle: https://docs.forgium.dev/docs/integration/capability-handoff - Request access: https://docs.forgium.dev/docs/integration/request-access - Contract retrieval: https://docs.forgium.dev/docs/integration/contract-retrieval - HTTP integration reference: https://docs.forgium.dev/docs/integration/reference-implementation If you are only testing connectivity, do not inspect or modify an unrelated repository: use the access bundle and the HTTP quickstart to send one message. Do not run repository or git discovery commands for a connectivity-only test. If you are implementing code, first confirm the working directory with `pwd` and explicitly inspect the host application's repository. Choose the minimum integration it actually needs: - HTTP when it needs a synchronous agent response; or - capabilities when the agent needs approved live data or actions from the host. Capabilities are optional and may coexist with HTTP. When a real API call or deployment is required, confirm these values for the selected environment before using them: - FORGIUM_AGENT_BASE_URL - FORGIUM_AGENT_API_KEY If either is missing, ask the Forgium administrator for the environment-specific access bundle and continue only with local implementation or mocks. Read the canonical OpenAPI contract before generating requests. If the agent cannot locate it through the published links, follow the Contract retrieval commands once and report the exact result. Do not substitute another contract. Implement only the applicable route, run tests, and record evidence. For capabilities, use the public lifecycle: protect and expose the host endpoint, provision its scoped credential through the Public API vault, create a secret-free manifest, import, contract-test, activate, and verify through chat. Repeat separately per environment. Never use a placeholder URL or an unauthenticated endpoint. If a published page or the canonical contract is unavailable, stop and report that blocker. Do not probe guessed OpenAPI, Swagger, API, or internal URLs. Report every blocker separately with its next action. Report changes, verification evidence, and every actionable blocker. Do not claim a capability is active unless activation and final chat verification pass. Never request Admin API access or internal secrets. ``` ## Expected result A successful run leaves a tested first HTTP message and a documented choice of HTTP or capabilities. Capability work is complete only after the target revision is active and a chat response is verified against the approved host endpoint. Continue with: - [Overview](overview.md) - [Getting started](getting-started.md) for the manual HTTP quickstart - [Environments](environments.md) - [Request access](request-access.md) - [Contract retrieval](contract-retrieval.md) - [HTTP integration reference](reference-implementation.md) - [Self-service business capabilities](capability-handoff.md) - [Public API contract](api.openapi.yaml) --- END docs/integration/use-with-an-agent.md --- --- BEGIN docs/integration/overview.md --- # Forgium Agent — Public API overview Forgium Agent is a conversational-agent service. Start with [Use Forgium Agent with an agent](use-with-an-agent.md) when a coding agent is doing the integration. Your application can send a user message to the Public API and receive an agent response. For automated discovery, use the [agent manifest](/agent-manifest.json). It publishes the canonical guides, raw OpenAPI contract, environment variables, and stop conditions. The manifest is the source for the generated [agent index](/agent-index.json) and [LLM index](/llms.txt). ## What you can build Choose the path that matches the host application: | Need | Use | |---|---| | A web, mobile, or backend application needs a synchronous agent reply | `POST /v1/channels/http/messages` | | The agent needs approved live data or actions from the host application | Self-service business capabilities | The HTTP channel currently accepts text messages. ## Access boundary Before integrating, ask the Forgium administrator for this access bundle for the target environment: ```bash FORGIUM_AGENT_BASE_URL=https:// FORGIUM_AGENT_API_KEY=mg_xxx ``` Use the key only with the Public API (`/v1/*`). If it is missing or rejected, ask the administrator for help. ## Recommended reading order For an agent: 1. [Use Forgium Agent with an agent](use-with-an-agent.md) — decision protocol. 2. [Environments](environments.md) — keep environments isolated. 3. [Request access](request-access.md) — obtain and validate the bundle when needed. 4. [Contract retrieval](contract-retrieval.md) — download and validate the raw contract if an agent cannot discover it through navigation. 5. [Authentication](auth.md) — API-key rules. 6. Read [Getting started](getting-started.md) for the HTTP quickstart, or [Self-service business capabilities](capability-handoff.md) when the host application must provide live data or actions. 7. Use the [OpenAPI contract](api.openapi.yaml) for exact request and response fields. For a server-side HTTP adapter, see [HTTP integration reference](reference-implementation.md). For a manual integration, start at [Getting started](getting-started.md). --- END docs/integration/overview.md --- --- BEGIN docs/integration/environments.md --- # Environments Keep Forgium Agent access, host-application endpoints, and credentials isolated by environment. A capability registered in one environment is not a deployment mechanism for another. ## Access bundles Request a separate bundle from the platform operator for every environment you will use: ```bash # Example only; use values issued by the Forgium administrator. FORGIUM_AGENT_BASE_URL=https:// FORGIUM_AGENT_API_KEY=mg_ ``` Never point a production host application at a development or staging API key. Never reuse a capability endpoint token across environments unless its owning application explicitly authorizes that use. | Environment | Intended use | Capability endpoint | |---|---|---| | Development | Local implementation and contract preparation | Local endpoint for direct tests; an authorized HTTPS tunnel is required before a deployed Worker can call it. | | Staging | End-to-end verification before release | Staging HTTPS endpoint, staging credential reference, and staging Forgium Agent access bundle. | | Production | Customer traffic | Production HTTPS endpoint, production credential reference, and production Forgium Agent access bundle. | ## Promotion workflow Repeat the capability lifecycle in each target environment; do not copy a staging capability ID or credential reference into production. 1. Deploy the host application's endpoint to the target environment and verify its scoped-token authentication directly. 2. Use the target environment's `FORGIUM_AGENT_*` bundle to store that endpoint token with `PUT /v1/capability-credentials/{credentialRef}`. 3. Import the target environment's manifest with its exact HTTPS URL. 4. Contract-test the imported capability, then activate it. 5. Send a real chat request to verify that the agent used the target endpoint. See [business capabilities](capability-handoff.md) for the manifest and API commands. ## Release safety Before production activation, verify all of the following: - the base URL and API key belong to production; - the manifest contains the production endpoint URL and no secrets; - the endpoint accepts only its production scoped token; - the contract test passed for the current capability revision; and - a chat smoke test returns a result grounded in the production endpoint. ## Staging E2E gate The repository includes two independent generic HTTPS reference consumers and a release-gate command: ```bash FORGIUM_E2E_ENV=staging bun run test:e2e:staging ``` The command requires the explicit staging URL, API key, control token, two consumer URLs/tokens/control tokens, and a second access-bundle key for the isolation assertion. It rejects non-HTTPS URLs, configured production hosts, missing inputs, and guessed defaults. It emits only a redacted report. The consumer setup, reset, and token-rotation endpoints exist only in staging and accept synthetic data. ## Rollback If a newly activated capability behaves incorrectly, disable it: ```bash curl -fsS -X POST "$FORGIUM_AGENT_BASE_URL/v1/capabilities/$CAPABILITY_ID/disable" \ -H "Authorization: Bearer $FORGIUM_AGENT_API_KEY" ``` Then correct the host endpoint or manifest, revise the capability, run its contract test, and reactivate it. If the API key or endpoint token may have leaked, notify the Forgium administrator and rotate the affected secret before resuming traffic. --- END docs/integration/environments.md --- --- BEGIN docs/integration/request-access.md --- # Request access The Public API access bundle is issued out of band by the Forgium administrator. The operator must configure the approved recipient and channel for each environment; this public contract does not assume a specific ticketing system, chat room, or email address. ## What to request Send the following template through the operator-approved channel: ```text Subject: Forgium Agent Public API access request Application: Owner: Environment: Purpose: Callback or host endpoint: Please provide the environment-specific access bundle through the approved secret-sharing channel. I need: - FORGIUM_AGENT_BASE_URL - FORGIUM_AGENT_API_KEY Do not include the API key in this ticket, repository, prompt, or log. ``` The operator may require additional application or deployment details before issuing access. Do not invent a URL, key, credential reference, or environment. ## Validate the bundle After receiving the values, keep them in the host application's secret manager and validate the environment without echoing the key: ```bash export FORGIUM_AGENT_BASE_URL="" export FORGIUM_AGENT_API_KEY="" curl -fsS "$FORGIUM_AGENT_BASE_URL/health" curl -fsS "$FORGIUM_AGENT_BASE_URL/v1/capabilities" \ -H "Authorization: Bearer $FORGIUM_AGENT_API_KEY" ``` The first response must identify the Forgium Agent API. The authenticated request must succeed for the intended environment. A `401` means the key is missing, invalid, expired, revoked, or paired with the wrong host; ask the administrator to reissue the matching bundle rather than trying another environment's key. For a capability, also verify that the endpoint URL and endpoint credential belong to the same environment before importing the manifest. See [Environments](environments.md) and [Self-service business capabilities](capability-handoff.md). ## Security boundary - Never commit an API key or host-endpoint token. - Never place secrets in `forgium-agent.capabilities.json`, prompts, screenshots, persisted agent context, or logs. - Request only the Public API bundle. Admin API tokens, platform secrets, and internal bindings are outside the integration contract. - If a secret may have been exposed, stop and ask the administrator to rotate it before continuing. --- END docs/integration/request-access.md --- --- BEGIN docs/integration/getting-started.md --- # Getting started This path uses the HTTP channel to verify that your application can send a text message and receive a synchronous agent response. ## 1. Receive the access bundle [Request the access bundle](request-access.md) from the Forgium administrator for the target environment. It contains: ```bash FORGIUM_AGENT_BASE_URL=https:// FORGIUM_AGENT_API_KEY=mg_xxx ``` Store the key in the host application's secret manager; do not commit it, include it in a capability manifest, or put it in logs. ## 2. Configure the integration If either value is unavailable, stop here and use [Request access](request-access.md). Do not substitute a guessed host, placeholder URL, or another environment's key. ```bash export FORGIUM_AGENT_BASE_URL="https://" export FORGIUM_AGENT_API_KEY="mg_xxx" ``` Confirm the public API is reachable: ```bash curl -fsS "$FORGIUM_AGENT_BASE_URL/health" ``` Expected response: ```json {"status":"ok","service":"agent-api"} ``` ## 3. Send the first message ```bash curl -fsS -X POST "$FORGIUM_AGENT_BASE_URL/v1/channels/http/messages" \ -H "Authorization: Bearer $FORGIUM_AGENT_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "user_id": "integration-smoke-test", "message": { "type": "text", "body": "Hello, can you help me?" }, "metadata": { "source": "integration-smoke-test" } }' ``` A successful response contains a `conversation_id` and an assistant `message`. This is the completion evidence for a connectivity-only test. Persist the `conversation_id` in the host application and send it in later requests to continue the same conversation. ```json { "conversation_id": "conv_xxx", "message": { "id": "msg_xxx", "role": "assistant", "type": "text", "body": "..." } } ``` ## 4. Select the next integration task - Register a [business capability](capability-handoff.md) when the agent needs data or an action from the host application. - Read [authentication](auth.md) before handling `401` responses or storing the key in deployment configuration. - Read [environments](environments.md) before promoting an integration beyond development. ## Troubleshooting | Response | Meaning | Next action | |---|---|---| | `401` | The API key is missing, invalid, expired, revoked, or unavailable for this environment. | Ask the Forgium administrator for a replacement. | | `422` | The request body is invalid. | Send a `message` with `type: "text"` and a non-empty `body`. | | `500` | The agent runtime could not complete the request. | Retry only if the host application's retry policy allows it; retain the response details and contact the operator if it persists. | The [OpenAPI contract](api.openapi.yaml) is authoritative for all request and response fields. If an agent cannot locate the contract, use the exact commands in [Contract retrieval](contract-retrieval.md); do not substitute another contract. For staging or production, validate the bundle and environment isolation described in [Environments](environments.md). For a server-side adapter pattern, error mapping, conversation handling, and production security checklist, see [HTTP integration reference](reference-implementation.md). --- END docs/integration/getting-started.md --- --- BEGIN docs/integration/reference-implementation.md --- # HTTP integration reference implementation This guide describes a minimal server-side adapter for an application that needs a synchronous Forgium Agent response. It is a development pattern, not a required framework or deployment model. ## Recommended boundary Keep the Forgium API key and upstream URL behind the host application's backend: ```text Client or UI │ │ POST /api/agent/messages ▼ Host application adapter │ validates input, authenticates the caller, │ applies timeout/rate limit, maps errors │ │ POST /v1/channels/http/messages ▼ Forgium Agent Public API ``` Do not call Forgium directly from a browser or mobile client when doing so would expose `FORGIUM_AGENT_API_KEY`. ## Example adapter contract The host application may expose a route such as `POST /api/agent/messages`. The exact route and framework belong to the host application. A small JSON contract is sufficient: ```json { "message": "Hello, can you help me?", "conversationId": "conv_optional" } ``` The adapter maps that request to the public HTTP channel contract: ```json { "user_id": "host-user-id", "conversation_id": "conv_optional", "message": { "type": "text", "body": "Hello, can you help me?" } } ``` The upstream response uses `conversation_id`; the host adapter may expose the same value as `conversationId` to match its own naming conventions. Preserve that identifier for subsequent messages in the same conversation. If the response includes `pending_action`, render the host application's own confirmation UI and approve or reject it only from the host backend. Never send the Forgium API key to that UI. The public [OpenAPI contract](api.openapi.yaml) is authoritative for the upstream request and response shape. Do not generate a different upstream payload from this example. ## Configuration Read these values only on the server: ```bash FORGIUM_AGENT_BASE_URL= FORGIUM_AGENT_API_KEY= ``` Fail clearly when configuration is absent. A local adapter can return a configuration error without making an upstream request; this is useful for local smoke tests. Never include the key in a response, source file, client bundle, capability manifest, log, or persisted agent context. ## Error and resilience behavior The adapter should make failures actionable without leaking upstream secrets: | Situation | Recommended behavior | |---|---| | Missing configuration | Return a stable configuration error and HTTP `503`; do not call Forgium. | | Invalid caller input | Return a validation error and HTTP `4xx`; do not call Forgium. | | Forgium rejects authentication | Return a dependency/authentication error, redact the key, and request a matching environment bundle. | | Forgium times out or is unavailable | Apply the host retry policy, then return a dependency error with a correlation ID. | | Unexpected upstream response | Validate the response before returning it and log only safe diagnostics. | Choose status codes that match the host application's existing API conventions. Do not retry validation, authentication, or non-idempotent requests blindly. Follow the [idempotency guide](idempotency.md) when adding retries or replay protection. ## Production checklist Before exposing the adapter to customer traffic: - [ ] Authenticate the host application's caller. - [ ] Apply rate limiting and an appropriate request body limit. - [ ] Keep `FORGIUM_AGENT_API_KEY` server-side and store it in a secret manager. - [ ] Configure an explicit timeout and bounded retry policy. - [ ] Redact API keys and message contents from logs unless the product has an approved data-retention policy. - [ ] Validate both incoming input and the external response. - [ ] Preserve `conversation_id` only according to the host application's privacy and retention requirements. - [ ] Treat `pending_action` as a server-side approval workflow, not a client-side command. - [ ] Add tests for missing configuration, invalid input, upstream `401`, timeout, malformed response, and successful conversation continuation. - [ ] Run the authenticated smoke test against the intended environment. The host application's authentication and rate limiting are not supplied by Forgium. They remain required even when the Forgium API key is valid. ## Definition of done A minimal HTTP integration is ready for review when: 1. local tests pass with mocked upstream responses; 2. `/health` or the host equivalent reports dependency configuration without revealing secrets; 3. the adapter sends the exact payload described by the public contract; 4. the response is validated and the conversation identifier is preserved; and 5. an authenticated smoke test passes for the target environment, or the access bundle is documented as the remaining blocker. See [Getting started](getting-started.md) for the first authenticated message and [Contract retrieval](contract-retrieval.md) when an agent cannot locate the canonical OpenAPI file. --- END docs/integration/reference-implementation.md --- --- BEGIN docs/integration/contract-retrieval.md --- # Retrieve and validate the public contract Use this guide when a coding agent cannot find the OpenAPI or API reference through the documentation navigation. The contract is public and does not require an API key. ## Canonical resources Use the published machine-readable manifest first: ```text https://docs.forgium.dev/agent-manifest.json ``` The canonical raw OpenAPI file is: ```text https://docs.forgium.dev/docs/integration/api.openapi.yaml ``` The same link is published from the [agent entrypoint](use-with-an-agent.md), the [LLM index](/llms.txt), and the [agent index](/agent-index.json). Do not infer an API host from the OpenAPI document. The API host comes from the environment-specific `FORGIUM_AGENT_BASE_URL` access bundle. ## Direct retrieval A shell-based agent can retrieve the file without a search engine or URL enumeration: ```bash CONTRACT_URL="https://docs.forgium.dev/docs/integration/api.openapi.yaml" curl -fsSL \ -H 'Accept: application/yaml,text/plain' \ "$CONTRACT_URL" \ -o /tmp/forgium-agent.openapi.yaml ``` Confirm that the response is the raw contract rather than an HTML error page: ```bash test -s /tmp/forgium-agent.openapi.yaml grep -q '^openapi:' /tmp/forgium-agent.openapi.yaml head -20 /tmp/forgium-agent.openapi.yaml ``` When the local toolchain has Redocly available, validate the syntax and references: ```bash bunx @redocly/cli lint /tmp/forgium-agent.openapi.yaml ``` The expected contract version is published in `agent-manifest.json` and in the OpenAPI `info.version` field. Do not silently continue with a different version. ## If retrieval fails Stop and report the concrete failure when any of these conditions occurs: - the manifest or raw contract returns a non-success HTTP status; - the response is HTML, empty, or does not contain an `openapi:` declaration; - the downloaded contract fails validation; or - the contract version does not match the published manifest. Report the URL, HTTP status, content type, and the next action. Do not try undocumented `openapi.json`, `swagger.json`, API, or internal URLs. Do not substitute a contract found through an unrelated search result. Example blocker report: ```text Blocker: https://docs.forgium.dev/docs/integration/api.openapi.yaml returned HTTP 404 with Content-Type text/html. Next action: deploy the public documentation artifact containing the canonical OpenAPI file, then rerun the retrieval and lint commands. ``` Missing API credentials is a separate blocker from a missing documentation contract. Report both when both are present. ## Contract evidence for an integration Record these facts in the implementation handoff: - canonical contract URL; - HTTP status and content type; - OpenAPI version and `info.version`; - lint result or the reason lint could not run; and - whether the authenticated API smoke test was run. A local adapter may be implemented with mocks while credentials are pending, but it must be labelled locally verified rather than end-to-end verified. --- END docs/integration/contract-retrieval.md --- --- BEGIN docs/integration/capability-handoff.md --- # Self-service business capabilities Use this document when your application's chat needs live data or actions from your application. An integrator can register and activate capabilities through the Public API with its API key. ## Lifecycle ```txt Implement endpoint + scoped token → test endpoint → expose HTTPS URL → encrypt token in vault → import draft → contract test → activate → verify chat response ``` The API key determines which capabilities the request can manage. No account or organization identifier is required in the manifest or URL. ## Endpoint requirements Your endpoint must: - use an exact public `https://` URL on port `443` in the manifest; - accept and return `application/json`; - validate input and enforce its business rules; - return only fields approved for the chat; and - have a stable request and response contract. A local JSON-backed endpoint is valid for development, but `localhost` cannot be called by deployed Workers. Test it locally first, then use an authorized HTTPS tunnel for a development test or deploy it through the application's authorized deployment path. Do not use an example or placeholder URL. For person lookup, prefer one read-only endpoint: ```http POST https://api.example.com/v1/people/lookup Content-Type: application/json {"name":"Juan Pérez"} ``` ```json { "person_id": "person_123", "name": "Juan Pérez", "email": "juan@example.com" } ``` ## Create `/forgium-agent.capabilities.json` Use the real endpoint URL. Every endpoint must be protected with a scoped token. Register the token in the vault first; never put a token or private header in the manifest. ```json { "domain": "people", "capabilities": [ { "name": "lookup_person", "description": "Looks up a person's approved contact details by name or DNI.", "when_to_use": "Use when the user asks for a person's email, contact details, or data by DNI.", "method": "POST", "url": "https://your-reachable-host.example/v1/people/lookup", "auth": { "type": "bearer", "credential_ref": "cred_people_api" }, "safe_headers": { "accept": "application/json", "content-type": "application/json" }, "input_schema": { "type": "object", "additionalProperties": false, "properties": { "name": { "type": "string", "maxLength": 200 }, "dni": { "type": "string", "maxLength": 20 } }, "anyOf": [{ "required": ["name"] }, { "required": ["dni"] }] }, "output_schema": { "type": "object", "additionalProperties": false, "required": ["person_id", "name"], "properties": { "person_id": { "type": "string", "maxLength": 100 }, "name": { "type": "string", "maxLength": 200 }, "email": { "type": "string", "maxLength": 254 }, "phone": { "type": "string", "maxLength": 50 } } }, "business_rules": ["The backend is authoritative for person data."], "examples": [], "side_effect": "read", "requires_approval": false, "timeout_ms": 5000, "retry_count": 1 } ] } ``` Every model-visible string needs `maxLength`; arrays need `maxItems`; objects need `additionalProperties: false`. ## Register, test, and activate ```bash export CAPABILITY_ID="" # Store only the endpoint token from the host secret manager. # This request stores only AES-GCM ciphertext in the credential vault. curl -fsS -X PUT "$FORGIUM_AGENT_BASE_URL/v1/capability-credentials/cred_people_api" \ -H "Authorization: Bearer $FORGIUM_AGENT_API_KEY" \ -H "Content-Type: application/json" \ -d "$(printf '{\"auth_type\":\"bearer\",\"secret\":%s}' "$(jq -Rn --arg value "$CAPABILITY_ENDPOINT_TOKEN" '$value')")" IMPORT_RESPONSE="$(curl -fsS -X POST "$FORGIUM_AGENT_BASE_URL/v1/capabilities/import" \ -H "Authorization: Bearer $FORGIUM_AGENT_API_KEY" \ -H "Content-Type: application/json" \ -H "Idempotency-Key: capability-import-$(date +%s)" \ --data-binary @forgium-agent.capabilities.json)" # Read the returned capabilities[0].id into CAPABILITY_ID with your JSON tool. curl -fsS -X POST "$FORGIUM_AGENT_BASE_URL/v1/capabilities/$CAPABILITY_ID/test" \ -H "Authorization: Bearer $FORGIUM_AGENT_API_KEY" \ -H "Content-Type: application/json" \ -d '{"arguments":{"name":"Juan Pérez"}}' curl -fsS -X POST "$FORGIUM_AGENT_BASE_URL/v1/capabilities/$CAPABILITY_ID/activate" \ -H "Authorization: Bearer $FORGIUM_AGENT_API_KEY" ``` Useful routes: | Operation | Route | |---|---| | List own capabilities | `GET /v1/capabilities` | | Import draft | `POST /v1/capabilities/import` | | Get or revise one | `GET` / `PATCH /v1/capabilities/{capabilityId}` | | Contract test | `POST /v1/capabilities/{capabilityId}/test` | | Activate or disable | `POST /v1/capabilities/{capabilityId}/activate` or `/disable` | ## Approved mutations A capability with `side_effect` other than `read` must also declare a non-destructive contract: ```json "side_effect": "create", "requires_approval": true, "idempotency_header": "Idempotency-Key", "test": { "mode": "dry_run", "header_name": "X-Dry-Run", "header_value": "true" } ``` The host endpoint must perform no externally observable mutation when the dry- run header is present. Activation is blocked until the current revision's dry- run passes. At runtime, the host application presents the `pending_action`, then calls the [approval protocol](capability-action-approval.md) from its server. Forgium never prescribes the confirmation UI. ## Credentials Provision the endpoint token through `PUT /v1/capability-credentials/{credentialRef}` before importing its manifest. The secret is AES-GCM ciphertext at rest; it is never returned by the API. | `auth.type` | Required request fields | |---|---| | `bearer` | `auth_type: "bearer"`, `secret` | | `api_key` | `auth_type: "api_key"`, `header_name: "x-api-key"` or `"x-api-token"`, `secret` | | `basic` | `auth_type: "basic"`, `secret` containing the pre-encoded Basic value | `auth.type: "none"` is rejected for self-service imports. Do not leave a business endpoint open just to make a capability work. ## Definition of done - [ ] Endpoint and local JSON data source implemented and directly tested. - [ ] Endpoint exposed at an exact reachable HTTPS URL on port 443. - [ ] Endpoint enforces its scoped token on every request. - [ ] Mutations declare and pass a non-destructive `dry_run` contract test. - [ ] Approval and rejection are handled server-to-server; the UI remains in the host application. - [ ] Token is provisioned through the credential vault and never appears in source, manifest, logs, or output. - [ ] Manifest contains the real URL, `credential_ref`, bounded schemas, and no secrets. - [ ] Import returns a draft capability. - [ ] Contract test passes for the imported revision. - [ ] Activation returns `lifecycle_status: "active"`. - [ ] The chat query produces a response grounded in the endpoint result. --- END docs/integration/capability-handoff.md --- --- BEGIN docs/integration/capability-action-approval.md --- # Capability action approval API Forgium returns a safe `pending_action` when a capability would change data or send an external message. The host application owns the confirmation screen and any step-up authentication. Forgium supplies only the server-to-server protocol. ## Read the action ```bash curl -fsS "$FORGIUM_AGENT_BASE_URL/v1/actions/$ACTION_ID" \ -H "Authorization: Bearer $FORGIUM_AGENT_API_KEY" ``` The response contains `action_id`, `summary`, `status`, `expires_at`, a sanitized `result` only after success, and a stable error code when execution fails. It never contains credentials, raw arguments, or endpoint payloads. ## Approve from the host backend ```bash curl -fsS -X POST "$FORGIUM_AGENT_BASE_URL/v1/actions/$ACTION_ID/approve" \ -H "Authorization: Bearer $FORGIUM_AGENT_API_KEY" \ -H "Idempotency-Key: approval-$REQUEST_ID" \ -H "Content-Type: application/json" \ -d '{"approved_by_subject":"opaque-host-user-id"}' ``` Approval is bound to the immutable capability revision, canonical arguments, expiry, asserted subject, and one durable upstream idempotency key. The state transition is compare-and-set: ```text pending → approved → executing → executed | failed pending → rejected ``` A fast result is `200`. A slow endpoint returns `202` with `status: executing`; poll `GET /v1/actions/{actionId}`. Repeating the same idempotency key returns the original response and never invokes the endpoint twice. A different key cannot approve an action that is no longer pending. Expired actions return `410 ACTION_EXPIRED`. ## Reject from the host backend ```bash curl -fsS -X POST "$FORGIUM_AGENT_BASE_URL/v1/actions/$ACTION_ID/reject" \ -H "Authorization: Bearer $FORGIUM_AGENT_API_KEY" \ -H "Idempotency-Key: rejection-$REQUEST_ID" \ -H "Content-Type: application/json" \ -d '{"rejected_by_subject":"opaque-host-user-id"}' ``` Rejection is atomic and never calls the capability endpoint. ## Verify the signed invocation Every endpoint invocation includes `Forgium-Context`, a compact Ed25519 JWS. Fetch the public keys from `/.well-known/forgium/capability-context/v1/jwks.json`, select `kid`, and reject unknown algorithms, key IDs, issuers, audiences, expired claims, reused `jti` values, mismatched method or URL, and a `body_sha256` that differs from the raw request body. Allow at most 60 seconds of clock skew. Store the replay key only until `exp`. The host endpoint remains responsible for its own authorization, business rules, and data protection. A valid Forgium signature proves request integrity and platform authorization; it does not prove the human's identity. --- END docs/integration/capability-action-approval.md --- --- BEGIN docs/integration/auth.md --- # Authentication — API key The Forgium administrator provides an API key for each environment. Use it with the Public API (`/v1/*`): ```http Authorization: Bearer ``` ## Obtain access Request these values from the Forgium administrator: ```bash FORGIUM_AGENT_BASE_URL= FORGIUM_AGENT_API_KEY= ``` Store the key in the host application's secret manager. Do not commit it, include it in a capability manifest, or put it in logs. If a request returns `401`, ask the administrator to verify or replace the key. Capability endpoints also receive a short-lived `Forgium-Context` Ed25519 JWS. Validate its issuer, audience, `kid`, time claims, exact method and URL, body hash, and replay ID before accepting a request. Retrieve verification keys from `/.well-known/forgium/capability-context/v1/jwks.json`; never request or store a private signing key. Rotate endpoint tokens with the [token rotation runbook](token-rotation.md). ## Example ```bash curl -fsS "$FORGIUM_AGENT_BASE_URL/v1/capabilities" \ -H "Authorization: Bearer $FORGIUM_AGENT_API_KEY" ``` --- END docs/integration/auth.md --- --- BEGIN docs/integration/errors.md --- # API errors The Public API uses JSON errors. The OpenAPI contract is authoritative for the status and shape of each route. Most Public API routes return: ```json { "error": "Invalid API key", "code": "UNAUTHORIZED" } ``` The HTTP channel returns a structured error object: ```json { "error": { "code": "VALIDATION_ERROR", "message": "Invalid JSON body" } } ``` ## Recovery guide | Status | Typical codes | Recovery | |---|---|---| | `400` | `VALIDATION_ERROR`, `INVALID_CREDENTIAL`, `MANIFEST_INVALID` | Fix the request using the OpenAPI schema; do not retry unchanged input. | | `401` | `UNAUTHORIZED` | Confirm the API key and base URL belong to the same environment; ask the administrator to reissue the bundle if needed. | | `404` | `CAPABILITY_NOT_FOUND`, `ACTION_NOT_FOUND`, `CREDENTIAL_NOT_FOUND` | Confirm the identifier belongs to the current access bundle. | | `405` | `METHOD_NOT_ALLOWED` | Use the method documented for the route. | | `409` | `CONFLICT`, `ACTION_NOT_PENDING`, `IDEMPOTENCY_KEY_REUSED`, `CONTRACT_TEST_REQUIRED`, `CREDENTIAL_NOT_CONFIGURED` | Resolve the current state, then retry the logical operation with the same idempotency key only when the request is unchanged. | | `410` | `ACTION_EXPIRED` | Ask the user to submit a new action; never retry the expired approval. | | `502` | `CAPABILITY_EXECUTION_UNAVAILABLE`, `UPSTREAM_*` | Inspect the sanitized action result and endpoint health; live mutations are not retried automatically. | | `413` | `REQUEST_TOO_LARGE` | Reduce the credential request to the documented limit. | | `422` | `VALIDATION_ERROR` | Send a text message with a non-empty body and valid fields. | | `500` | `AGENT_RUNTIME_ERROR`, `INTERNAL_ERROR` | Apply the host application's retry policy and retain the response code for support. | | `503` | `CREDENTIAL_VAULT_UNAVAILABLE` | Do not rotate repeatedly; retry according to the host policy and contact the operator if it persists. | Never log API keys, endpoint tokens, authorization headers, or complete request bodies containing secrets. For a suspected leak, stop and request rotation. --- END docs/integration/errors.md --- --- BEGIN docs/integration/idempotency.md --- # Idempotency ## Capability imports Every `POST /v1/capabilities/import` request requires an `Idempotency-Key` header. Generate one key for a single logical import and reuse that exact key when retrying the same request. ```bash -H "Idempotency-Key: capability-import-$(date +%s)" ``` A repeated import with the same key returns the previous result and includes `Idempotency-Replayed: true`; it does not create a second capability revision. Use a new key only for a new logical import, such as one containing a revised manifest. ## Action decisions Approval and rejection also require an `Idempotency-Key`. The key is scoped to the access bundle and stored with a request hash, action ID, operation, status, and redacted response. Reusing the same key with a different action, operation, or subject returns `409 IDEMPOTENCY_KEY_REUSED`. A capability mutation receives the stable `idempotency_key` persisted when its pending action was created. Forgium sends it as the manifest's `idempotency_header`, or `Idempotency-Key` when no custom header is declared. Forgium never retries a live mutation automatically. --- END docs/integration/idempotency.md --- --- BEGIN docs/integration/token-rotation.md --- # Capability endpoint token rotation runbook Endpoint tokens are environment-specific secrets. Use a different token for development, staging, and production; never copy a staging bundle into production. ## Planned rotation 1. Generate a new scoped token in the host application's secret manager. 2. Deploy the host endpoint so it accepts the old and new token during the short, documented grace period. 3. Store the new value with `PUT /v1/capability-credentials/{credentialRef}`. Forgium encrypts it with the environment vault key and never returns it. 4. Run the current capability contract test and record the capability revision, environment, timestamp, and result code. 5. Confirm a synthetic read or dry-run reaches the host endpoint with the new token. 6. After the grace period, revoke the old token in the host secret manager and verify that it receives `401`. 7. Record the operator, expiry of the grace period, and evidence without recording either token. The update is scoped to the authenticated access bundle and does not change a capability URL or its revision. If a capability should stop using a credential immediately, call: ```bash curl -fsS -X DELETE "$FORGIUM_AGENT_BASE_URL/v1/capability-credentials/$CREDENTIAL_REF" \ -H "Authorization: Bearer $FORGIUM_AGENT_API_KEY" ``` The response is `{ "credential_ref": "...", "status": "revoked" }`. A revoked credential blocks new endpoint calls and must be replaced before activation. ## Suspected leak Stop using the affected token, revoke it at the host endpoint, revoke the Forgium credential, issue a replacement, and inspect the security event trail for the affected capability. Do not paste the token into tickets, logs, chat, or a capability manifest. Rotate the Forgium API key or context signing key separately if either platform secret may also be exposed. ## Ownership and evidence The host application owns endpoint-token generation, endpoint acceptance, and old-token revocation. Forgium Operations owns vault storage, API-key bundles, and signing-key publication. Product/Security owns release approval. Evidence must contain only environment, credential reference, revision, stable result codes, and timestamps. --- END docs/integration/token-rotation.md --- --- BEGIN docs/integration/privacy-and-retention.md --- # Privacy and retention policy for the integration MVP This policy describes the minimum handling of data sent through Forgium. The host application remains responsible for its own user notice, lawful basis, access controls, and deletion obligations. ## Data classes | Class | Stored by Forgium | Purpose | Default retention | | --- | --- | --- | --- | | Message text | Conversation and message records | Generate and audit a reply | 30 days | | Action metadata | Action ID, capability ID/revision, status, expiry, subject IDs, hashes | Confirmation and execution | 30 days after terminal state | | Capability audit | IDs, SHA-256 hashes, timing, HTTP status, stable error codes | Security and operations | 90 days | | Credentials | AES-GCM ciphertext only | Authenticate an endpoint | Until revoked, then 30 days for deletion evidence | | Signing material | Private key in the Worker secret store only | Sign outbound context | Managed by key-rotation policy; never stored in D1 | Bodies, bearer tokens, complete JWS values, and capability arguments are not written to capability audit records. Staging fixtures use synthetic data only. ## Access, deletion, and support Access is limited to the authenticated host backend, the Forgium runtime for execution, and authorized Operations/Security personnel for incident response. Support access is time-limited, logged, and must use redacted identifiers. The host application can request deletion of conversations, messages, action records, credentials, and related audit records through the operational owner. Deletion requests are acknowledged with scope, timestamp, requester, and completion evidence. Legal holds or active incident investigations may delay deletions; the requester receives the reason and expected review date. ## Incidents For suspected disclosure, the host application must revoke the endpoint token and Forgium access bundle, preserve redacted evidence, and contact the platform incident owner. Forgium Operations rotates affected credentials or signing keys, reviews security events, and communicates impact and recovery steps. Never include secrets or raw message bodies in an incident ticket. This MVP policy requires Product, Legal, and Security approval before a production access bundle is issued. Changes to retention, data classes, or support access require a documented review. --- END docs/integration/privacy-and-retention.md --- --- BEGIN docs/integration/api.openapi.yaml --- openapi: 3.1.0 info: title: Forgium Agent Public API version: 2.1.0 description: | Stable public contract for sending messages to Forgium Agent and managing host-application capabilities. Authenticate with the API key issued for the target environment. contact: name: Forgium platform administrator license: name: Forgium public documentation terms identifier: LicenseRef-Forgium-Public-Docs servers: - url: https://{apiHost} description: Use the host from FORGIUM_AGENT_BASE_URL. Do not infer a host from this document. variables: apiHost: default: api.forgium.dev description: Hostname only, copied from FORGIUM_AGENT_BASE_URL. security: - bearerAuth: [] tags: - name: System description: Availability checks. - name: HTTP channel description: Synchronous text messaging. - name: Capabilities description: Self-service host-application capability lifecycle. - name: Actions description: Server-to-server approval of pending capability actions. paths: /health: get: operationId: getHealth summary: Check public API availability security: [] tags: [System] responses: '200': description: Public API is available. content: application/json: schema: $ref: '#/components/schemas/HealthResponse' example: status: ok service: agent-api '400': description: Invalid health-check request. content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' '503': description: Public API is temporarily unavailable. content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' /.well-known/forgium/capability-context/v1/jwks.json: get: operationId: getCapabilityContextJwks summary: Retrieve public keys for Forgium capability contexts security: [] tags: [System] responses: '200': description: Public Ed25519 verification keys. content: application/json: schema: $ref: '#/components/schemas/JwksResponse' '404': $ref: '#/components/responses/NotFound' '503': $ref: '#/components/responses/ServiceUnavailable' /v1/channels/http/messages: post: operationId: sendHttpMessage summary: Send a text message and receive a synchronous response tags: [HTTP channel] requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/HttpChannelRequest' example: user_id: mobile_user_123 message: type: text body: Hello, can you help me? metadata: platform: ios app_version: 1.0.0 responses: '200': description: Agent response. content: application/json: schema: $ref: '#/components/schemas/HttpChannelResponse' examples: answer: value: conversation_id: conv_abc123def456 message: id: msg_abc123def456 role: assistant type: text body: Hello, how can I help? pending_mutation: value: conversation_id: conv_abc123def456 message: id: msg_abc123def456 role: assistant type: text body: Necesito tu aprobación antes de realizar esa acción. pending_action: action_id: sa_abc123def456 summary: La capacidad create_appointment requiere confirmación. status: pending expires_at: '2026-08-02T16:05:00Z' '401': $ref: '#/components/responses/Unauthorized' '405': $ref: '#/components/responses/HttpMethodNotAllowed' '409': $ref: '#/components/responses/HttpDuplicateEvent' '413': $ref: '#/components/responses/HttpRequestTooLarge' '422': $ref: '#/components/responses/HttpValidationError' '500': $ref: '#/components/responses/HttpRuntimeError' /v1/actions/{actionId}: get: operationId: getAction summary: Read a pending action status description: The API key scopes the action implicitly. Arguments, credentials, and raw payloads are never returned. tags: [Actions] parameters: - $ref: '#/components/parameters/ActionId' responses: '200': description: Safe action status. content: application/json: schema: $ref: '#/components/schemas/ActionResponse' '401': $ref: '#/components/responses/Unauthorized' '404': $ref: '#/components/responses/NotFound' /v1/actions/{actionId}/approve: post: operationId: approveAction summary: Approve and execute one pending action description: Approval is atomic, idempotent, and executes only the immutable capability revision and arguments that created the action. A slow execution returns 202. tags: [Actions] parameters: - $ref: '#/components/parameters/ActionId' - $ref: '#/components/parameters/IdempotencyKey' requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/ApproveActionRequest' example: approved_by_subject: opaque-operator-42 responses: '200': description: Action executed synchronously. content: application/json: schema: $ref: '#/components/schemas/ActionResponse' '202': description: Execution continues asynchronously; poll GET /v1/actions/{actionId}. content: application/json: schema: $ref: '#/components/schemas/ActionResponse' '400': $ref: '#/components/responses/ValidationError' '401': $ref: '#/components/responses/Unauthorized' '404': $ref: '#/components/responses/NotFound' '409': $ref: '#/components/responses/Conflict' '410': $ref: '#/components/responses/Expired' '502': $ref: '#/components/responses/UpstreamFailure' /v1/actions/{actionId}/reject: post: operationId: rejectAction summary: Reject one pending action description: Rejection is atomic and never invokes the capability endpoint. tags: [Actions] parameters: - $ref: '#/components/parameters/ActionId' - $ref: '#/components/parameters/IdempotencyKey' requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/RejectActionRequest' example: rejected_by_subject: opaque-operator-42 responses: '200': description: Action rejected. content: application/json: schema: $ref: '#/components/schemas/ActionResponse' '400': $ref: '#/components/responses/ValidationError' '401': $ref: '#/components/responses/Unauthorized' '404': $ref: '#/components/responses/NotFound' '409': $ref: '#/components/responses/Conflict' '410': $ref: '#/components/responses/Expired' /v1/capability-credentials/{credentialRef}: delete: operationId: revokeCapabilityCredential summary: Revoke a stored host-endpoint credential tags: [Capabilities] parameters: - $ref: '#/components/parameters/CredentialRef' responses: '200': description: Credential revoked and no longer usable. content: application/json: schema: $ref: '#/components/schemas/CredentialResponse' '401': $ref: '#/components/responses/Unauthorized' '404': $ref: '#/components/responses/NotFound' '503': $ref: '#/components/responses/ServiceUnavailable' put: operationId: configureCapabilityCredential summary: Store or rotate a host-endpoint credential description: The secret is encrypted at rest and is never returned or included in a capability manifest. tags: [Capabilities] parameters: - $ref: '#/components/parameters/CredentialRef' requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/CredentialRequest' example: auth_type: bearer secret: endpoint-token-from-secret-manager responses: '201': description: Credential configured. The secret is not returned. content: application/json: schema: $ref: '#/components/schemas/CredentialResponse' '400': $ref: '#/components/responses/ValidationError' '401': $ref: '#/components/responses/Unauthorized' '413': description: Request exceeds the credential size limit. content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' '503': description: Credential vault is unavailable. content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' /v1/capabilities: get: operationId: listCapabilities summary: List capabilities available to the API key tags: [Capabilities] responses: '200': description: Capability definitions scoped to the API key. content: application/json: schema: $ref: '#/components/schemas/CapabilityListResponse' '401': $ref: '#/components/responses/Unauthorized' /v1/capabilities/import: post: operationId: importCapabilities summary: Import capabilities as drafts description: Import does not activate a capability. A contract test is required before activation. tags: [Capabilities] parameters: - $ref: '#/components/parameters/IdempotencyKey' requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/CapabilityManifest' responses: '201': description: Draft capabilities created. content: application/json: schema: $ref: '#/components/schemas/CapabilityImportResponse' '400': $ref: '#/components/responses/ValidationError' '401': $ref: '#/components/responses/Unauthorized' '409': $ref: '#/components/responses/Conflict' /v1/capabilities/{capabilityId}: get: operationId: getCapability summary: Get one capability tags: [Capabilities] parameters: - $ref: '#/components/parameters/CapabilityId' responses: '200': description: Capability definition and revision history. content: application/json: schema: $ref: '#/components/schemas/CapabilityDetailResponse' '401': $ref: '#/components/responses/Unauthorized' '404': $ref: '#/components/responses/NotFound' patch: operationId: reviseCapability summary: Create a draft revision of a capability description: If-Match must contain the current numeric revision. The revised capability must be tested again. tags: [Capabilities] parameters: - $ref: '#/components/parameters/CapabilityId' - $ref: '#/components/parameters/IfMatch' requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/CapabilityPatchRequest' responses: '200': description: Draft revision created. content: application/json: schema: $ref: '#/components/schemas/CapabilityLifecycleResponse' '400': $ref: '#/components/responses/ValidationError' '401': $ref: '#/components/responses/Unauthorized' '404': $ref: '#/components/responses/NotFound' '409': $ref: '#/components/responses/Conflict' /v1/capabilities/{capabilityId}/test: post: operationId: testCapability summary: Run a contract test for a capability revision description: Reads call the normal endpoint. Mutations must declare test.mode=dry_run; Forgium sends the declared header and activation remains blocked until this non-destructive test passes. tags: [Capabilities] parameters: - $ref: '#/components/parameters/CapabilityId' requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/CapabilityTestRequest' example: arguments: name: Juan Pérez responses: '200': description: Contract test result. content: application/json: schema: $ref: '#/components/schemas/CapabilityTestResponse' '401': $ref: '#/components/responses/Unauthorized' '404': $ref: '#/components/responses/NotFound' '409': $ref: '#/components/responses/Conflict' /v1/capabilities/{capabilityId}/activate: post: operationId: activateCapability summary: Activate a tested capability tags: [Capabilities] parameters: - $ref: '#/components/parameters/CapabilityId' responses: '200': description: Capability is active. content: application/json: schema: $ref: '#/components/schemas/CapabilityLifecycleResponse' '401': $ref: '#/components/responses/Unauthorized' '404': $ref: '#/components/responses/NotFound' '409': $ref: '#/components/responses/Conflict' /v1/capabilities/{capabilityId}/disable: post: operationId: disableCapability summary: Disable a capability tags: [Capabilities] parameters: - $ref: '#/components/parameters/CapabilityId' responses: '200': description: Capability is disabled. content: application/json: schema: $ref: '#/components/schemas/CapabilityLifecycleResponse' '401': $ref: '#/components/responses/Unauthorized' '404': $ref: '#/components/responses/NotFound' components: securitySchemes: bearerAuth: type: http scheme: bearer description: API key issued out of band by the Forgium administrator. parameters: CredentialRef: name: credentialRef in: path required: true schema: type: string pattern: '^cred_[A-Za-z0-9_-]{3,120}$' minLength: 7 maxLength: 128 CapabilityId: name: capabilityId in: path required: true schema: type: string pattern: '^cap_[a-z0-9]+$' minLength: 8 maxLength: 80 ActionId: name: actionId in: path required: true schema: type: string pattern: '^[a-zA-Z0-9_-]{1,128}$' minLength: 1 maxLength: 128 IdempotencyKey: name: Idempotency-Key in: header required: true schema: type: string minLength: 1 maxLength: 200 IfMatch: name: If-Match in: header required: true schema: type: string minLength: 1 maxLength: 80 schemas: HealthResponse: type: object additionalProperties: false required: [status, service] properties: status: type: string enum: [ok] maxLength: 16 service: type: string maxLength: 64 HttpChannelRequest: type: object additionalProperties: false required: [message] properties: conversation_id: type: string minLength: 1 maxLength: 128 user_id: type: string minLength: 1 maxLength: 200 message: $ref: '#/components/schemas/TextMessageRequest' metadata: type: object additionalProperties: type: string maxLength: 500 maxProperties: 30 TextMessageRequest: type: object additionalProperties: false required: [type, body] properties: type: type: string enum: [text] maxLength: 16 body: type: string minLength: 1 maxLength: 10000 HttpChannelResponse: type: object additionalProperties: false required: [conversation_id, message] properties: conversation_id: type: string minLength: 1 maxLength: 128 message: $ref: '#/components/schemas/AssistantMessage' pending_action: $ref: '#/components/schemas/PendingAction' PendingAction: type: object additionalProperties: false required: [action_id, summary, status, expires_at] properties: action_id: type: string maxLength: 128 summary: type: string minLength: 1 maxLength: 500 status: type: string enum: [pending] expires_at: type: string format: date-time maxLength: 64 ActionResponse: type: object additionalProperties: false required: [action_id, status, summary, expires_at, result, error] properties: action_id: type: string maxLength: 128 status: type: string enum: [pending, approved, executing, executed, rejected, failed, expired] maxLength: 16 summary: type: string maxLength: 500 expires_at: type: string format: date-time maxLength: 64 result: type: [object, array, string, number, boolean, 'null'] description: Sanitized result restricted to the capability output schema. error: oneOf: - $ref: '#/components/schemas/SafeActionError' - type: 'null' SafeActionError: type: object additionalProperties: false required: [code] properties: code: type: string maxLength: 100 ApproveActionRequest: type: object additionalProperties: false required: [approved_by_subject] properties: approved_by_subject: type: string minLength: 1 maxLength: 128 RejectActionRequest: type: object additionalProperties: false required: [rejected_by_subject] properties: rejected_by_subject: type: string minLength: 1 maxLength: 128 AssistantMessage: type: object additionalProperties: false required: [id, role, type, body] properties: id: type: string minLength: 1 maxLength: 128 role: type: string enum: [assistant] maxLength: 16 type: type: string enum: [text] maxLength: 16 body: type: string maxLength: 20000 CredentialRequest: type: object additionalProperties: false required: [auth_type, secret] properties: auth_type: type: string enum: [bearer, api_key, basic] maxLength: 16 header_name: type: string enum: [x-api-key, x-api-token] maxLength: 32 secret: type: string minLength: 1 maxLength: 4096 CredentialResponse: type: object additionalProperties: false required: [credential_ref, status] properties: credential_ref: type: string maxLength: 128 status: type: string enum: [configured, revoked] maxLength: 32 JwksResponse: type: object additionalProperties: false required: [keys] properties: keys: type: array minItems: 1 maxItems: 10 items: $ref: '#/components/schemas/PublicSigningKey' PublicSigningKey: type: object additionalProperties: false required: [kty, crv, x, kid, use, alg] properties: kty: type: string enum: [OKP] crv: type: string enum: [Ed25519] x: type: string maxLength: 128 kid: type: string minLength: 1 maxLength: 128 use: type: string enum: [sig] alg: type: string enum: [EdDSA] CapabilityManifest: type: object additionalProperties: false required: [domain, capabilities] properties: domain: type: string pattern: '^[a-z][a-z0-9_-]{1,63}$' minLength: 2 maxLength: 64 capabilities: type: array minItems: 1 maxItems: 50 items: $ref: '#/components/schemas/CapabilityDefinition' CapabilityDefinition: type: object additionalProperties: false required: [name, description, when_to_use, method, url, auth, safe_headers, input_schema, output_schema, side_effect, requires_approval, timeout_ms, retry_count] properties: name: type: string pattern: '^[a-z][a-z0-9_]{1,63}$' minLength: 2 maxLength: 64 description: type: string minLength: 1 maxLength: 1000 when_to_use: type: string minLength: 1 maxLength: 1000 method: type: string enum: [GET, POST, PUT, PATCH, DELETE] maxLength: 6 url: type: string format: uri pattern: '^https://' maxLength: 2048 allowed_host: type: string maxLength: 253 auth: $ref: '#/components/schemas/CapabilityAuth' safe_headers: type: object additionalProperties: false properties: accept: type: string maxLength: 100 content-type: type: string enum: [application/json] maxLength: 100 input_schema: $ref: '#/components/schemas/JsonSchemaDocument' output_schema: $ref: '#/components/schemas/JsonSchemaDocument' business_rules: type: array maxItems: 50 items: type: string maxLength: 1000 examples: type: array maxItems: 20 items: type: object additionalProperties: true side_effect: type: string enum: [read, create, update, delete, external_send] maxLength: 32 requires_approval: type: boolean idempotency_header: type: string maxLength: 100 timeout_ms: type: integer minimum: 1000 maximum: 10000 retry_count: type: integer minimum: 0 maximum: 1 cache_ttl_seconds: type: integer minimum: 0 maximum: 86400 test: $ref: '#/components/schemas/DryRunContract' DryRunContract: type: object additionalProperties: false required: [mode, header_name, header_value] properties: mode: type: string enum: [dry_run] header_name: type: string pattern: '^x-[A-Za-z0-9-]{1,64}$' maxLength: 66 header_value: type: string minLength: 1 maxLength: 128 CapabilityAuth: type: object additionalProperties: false required: [type] properties: type: type: string enum: [bearer, api_key, basic, none] maxLength: 16 credential_ref: type: string pattern: '^cred_[A-Za-z0-9_-]{3,120}$' maxLength: 128 header_name: type: string enum: [x-api-key, x-api-token] maxLength: 32 JsonSchemaDocument: type: object description: Bounded JSON Schema document used to validate capability arguments or results. additionalProperties: true CapabilityImportResponse: type: object additionalProperties: false required: [capabilities] properties: capabilities: type: array maxItems: 50 items: $ref: '#/components/schemas/CapabilityLifecycleResponse' CapabilityListResponse: type: object additionalProperties: false required: [capabilities] properties: capabilities: type: array maxItems: 1000 items: $ref: '#/components/schemas/CapabilitySummary' CapabilitySummary: type: object unevaluatedProperties: false required: [id, name, description, when_to_use, input_schema, output_schema, business_rules, examples, side_effect, requires_approval, revision, lifecycle_status] properties: id: type: string maxLength: 80 name: type: string maxLength: 64 description: type: string maxLength: 1000 when_to_use: type: string maxLength: 1000 input_schema: $ref: '#/components/schemas/JsonSchemaDocument' output_schema: $ref: '#/components/schemas/JsonSchemaDocument' business_rules: type: array maxItems: 50 items: type: string maxLength: 1000 examples: type: array maxItems: 20 items: type: object additionalProperties: true side_effect: type: string maxLength: 32 requires_approval: type: boolean revision: type: integer minimum: 1 lifecycle_status: type: string enum: [draft, active, disabled] maxLength: 16 credential_configured: type: boolean updated_at: type: string format: date-time maxLength: 64 CapabilityDetailResponse: allOf: - $ref: '#/components/schemas/CapabilitySummary' - type: object unevaluatedProperties: false required: [method, url, revisions] properties: method: type: string maxLength: 6 url: type: string format: uri maxLength: 2048 revisions: type: array maxItems: 100 items: $ref: '#/components/schemas/CapabilityRevision' CapabilityRevision: type: object additionalProperties: false required: [revision, change_type, actor_type, actor_id, created_at] properties: revision: type: integer minimum: 1 change_type: type: string maxLength: 32 actor_type: type: string maxLength: 32 actor_id: type: string maxLength: 128 created_at: type: string format: date-time maxLength: 64 CapabilityPatchRequest: type: object additionalProperties: false required: [capability] properties: domain: type: string maxLength: 64 capability: $ref: '#/components/schemas/CapabilityDefinition' CapabilityTestRequest: type: object additionalProperties: false required: [arguments] properties: arguments: type: object additionalProperties: true CapabilityTestResponse: type: object additionalProperties: false required: [status, capability_id, revision] properties: status: type: string enum: [passed, failed] maxLength: 16 capability_id: type: string maxLength: 80 revision: type: integer minimum: 1 error_code: type: string maxLength: 100 CapabilityLifecycleResponse: type: object additionalProperties: false required: [id, lifecycle_status, revision] properties: id: type: string maxLength: 80 lifecycle_status: type: string enum: [draft, active, disabled] maxLength: 16 revision: type: integer minimum: 1 ErrorResponse: type: object additionalProperties: false required: [error, code] properties: error: type: string maxLength: 500 code: type: string maxLength: 100 HttpErrorResponse: type: object additionalProperties: false required: [error] properties: error: type: object additionalProperties: false required: [code, message] properties: code: type: string maxLength: 100 message: type: string maxLength: 500 details: type: object additionalProperties: true responses: Unauthorized: description: API key is missing, invalid, expired, or revoked. content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' example: error: Invalid API key code: UNAUTHORIZED ValidationError: description: Request body or parameter is invalid. content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' example: error: VALIDATION_ERROR code: VALIDATION_ERROR HttpMethodNotAllowed: description: HTTP method is not supported for this route. headers: Allow: schema: type: string maxLength: 100 content: application/json: schema: $ref: '#/components/schemas/HttpErrorResponse' HttpDuplicateEvent: description: The message event was already processed. content: application/json: schema: $ref: '#/components/schemas/HttpErrorResponse' HttpValidationError: description: The HTTP channel request is invalid. content: application/json: schema: $ref: '#/components/schemas/HttpErrorResponse' HttpRequestTooLarge: description: The HTTP channel body exceeds the boundary limit. content: application/json: schema: $ref: '#/components/schemas/HttpErrorResponse' HttpRuntimeError: description: The agent runtime could not produce a response. content: application/json: schema: $ref: '#/components/schemas/HttpErrorResponse' NotFound: description: Capability does not exist for this API key. content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' Conflict: description: The requested operation conflicts with the current capability state. content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' Expired: description: The action expired before the decision was accepted. content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' example: error: ACTION_EXPIRED code: ACTION_EXPIRED UpstreamFailure: description: The capability endpoint failed; no automatic mutation retry is performed. content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' ServiceUnavailable: description: The requested service is temporarily unavailable. content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' --- END docs/integration/api.openapi.yaml --- --- BEGIN docs/integration/agent-consumer-pack.md --- # Forgium Agent — integration package This exported package is the public contract for an external developer or AI agent integrating an application with Forgium Agent. > **Compatibility URL:** the canonical agent entrypoint is > [Use Forgium Agent with an agent](use-with-an-agent.md). This page remains > available so existing public links do not break. ## Start here Read the documents in this order: 1. [Overview](overview.md) — what Forgium Agent does and which integration path to choose. 2. [Getting started](getting-started.md) — receive the access bundle and send the first HTTP message. 3. [Environments](environments.md) — isolate development, staging, and production. 4. Choose the task-specific guide: - [Business capabilities](capability-handoff.md) for live data or actions from the host application. - [OpenAPI](api.openapi.yaml) for the complete Public API contract. The Skill source is not currently distributed as an installable artifact. Use the universal agent entrypoint above instead. ## Authority boundary The Forgium administrator provides this access bundle: ```bash FORGIUM_AGENT_BASE_URL=https:// FORGIUM_AGENT_API_KEY=mg_xxx ``` Use the API key with the Public API (`/v1/*`) to send messages and manage business capabilities. If either value is missing, ask the administrator. ## Completion paths | Goal | Completion condition | |---|---| | Send a message from a host application | A request to `POST /v1/channels/http/messages` returns an assistant message. | | Give the agent live business data or an action | A scoped host endpoint is imported, contract-tested, activated, and verified through chat. | A generic response to a domain query usually means the required business capability is absent or inactive. Follow the complete lifecycle in [capability-handoff.md](capability-handoff.md); do not substitute chat middleware, a proxy workaround, a placeholder URL, or an unauthenticated host endpoint. --- END docs/integration/agent-consumer-pack.md --- --- BEGIN docs/skill/micro-agent-integrator/SKILL.md --- --- name: micro-agent-integrator description: >- Optional workflow for integrating an external application with Forgium Agent over the public HTTP channel and host-application capabilities. version: 1.1.0 --- # Forgium Agent Integrator This source is public for runtimes that already support a local `SKILL.md`; it is not currently distributed through an installable package or registry. The canonical contract remains the public documentation. ## Read first `` means the root of the exported public documentation package. Read in this order: 1. `/integration/use-with-an-agent.md` 2. `/integration/overview.md` 3. `/integration/environments.md` 4. `/integration/request-access.md` when access is missing 5. `/integration/getting-started.md` for HTTP 6. `/integration/capability-handoff.md` for capabilities 7. `/integration/api.openapi.yaml` for exact schemas ## Workflow 1. Determine whether the task is connectivity-only or code integration. 2. For connectivity-only, do not inspect or modify an unrelated repository: use the access bundle and the HTTP quickstart to send one message. 3. For code integration, inspect the host repository and identify the requested behavior. Choose the minimum route: HTTP for a synchronous agent response, or capabilities for approved live host data/actions. Capabilities are optional. 4. Confirm `FORGIUM_AGENT_BASE_URL` and `FORGIUM_AGENT_API_KEY` only when a real API call or deployment is required. If either is missing, request the environment-specific bundle and continue with local work or mocks. 5. Implement only the selected route using the canonical guide and OpenAPI contract. Do not invent a data source, tunnel, framework, or deployment. 6. Run local tests and the applicable authenticated smoke test. 7. For capabilities, follow the canonical lifecycle: protect and expose the endpoint, provision its scoped credential, create a secret-free manifest, import, contract-test, activate, and verify through chat. Never use a placeholder URL or unauthenticated endpoint. 8. Report changes, verification evidence, and every actionable blocker. Do not claim a capability is active without successful activation and chat verification. ## Security boundary Use only the Public API with the supplied bundle. Never request Admin API credentials, platform secrets, internal bindings, or secrets from source control. Keep API keys and endpoint tokens out of manifests, prompts, logs, screenshots, and persisted agent context. --- END docs/skill/micro-agent-integrator/SKILL.md ---