> For the complete documentation index, see [llms.txt](https://faction-os.gitbook.io/faction-os-docs/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://faction-os.gitbook.io/faction-os-docs/apps/adapters/readme_adapters.md).

# @factionos/adapters

Outbound bridges from the FactionOS WebSocket broadcast to external chat and webhook destinations.

Three adapters ship today:

* Discord webhook.
* Telegram bot message.
* Generic HTTPS webhook POST.

Adapters are one-way, best-effort, and optional. They do not accept inbound commands from chat systems or webhook destinations.

Phase 19 adds a shared `channelCommandSource` helper for safe provider labels, delivery ids, source labels, and redacted metadata that server-side inbound intake can reuse. That helper does not turn adapter processes into inbound listeners; Discord, Telegram, and generic webhook adapters remain outbound bridges only.

## How It Works

```
FactionOS server (port 2468, ws)
  -> startBridge() in src/shared/wsBridge.ts
  -> formatEvent() in src/shared/formatter.ts
  -> ChannelThrottle
  -> Discord webhook, Telegram bot.sendMessage, or generic POST
```

Each adapter is a long-lived Node process. It can run on a different host when `FACTIONOS_WS_URL` points at a reachable FactionOS WebSocket endpoint. If the local server has `FACTIONOS_AUTH_TOKEN` enabled, set the same variable for the adapter so the WebSocket handshake can authenticate.

## Quick Start

```bash
cd apps/adapters
cp ../../.env.local.example ../../.env.local
# Fill in DISCORD_WEBHOOK_URL, TELEGRAM_BOT_TOKEN plus TELEGRAM_CHAT_ID,
# or FACTIONOS_WEBHOOK_URL for the generic webhook bridge.
npm install
npm run discord
# or: npm run telegram
# or: npm run webhook
```

Adapters auto-load env files in this order: root `.env.local`, root `.env`, `apps/adapters/.env.local`, then `apps/adapters/.env`. Already-exported shell variables keep priority over file values, earlier files win over later files, and blank placeholders are ignored. Prefer root `.env.local` for shared local values such as `FACTIONOS_AUTH_TOKEN`; use `apps/adapters/.env` only for adapter-specific fallback defaults or isolated adapter runs.

## Event Filtering

`FACTIONOS_ADAPTER_SEVERITY=high,medium` is the default. The formatter classifies accepted events as:

* `high`: permission requests and hero errors.
* `medium`: mission completes, War Room joined, awaiting-input or dismissed hero states, and notice posts.
* `low`: hero spawns, generated plans, scrolls, achievements, and analysis summaries.

Set `FACTIONOS_ADAPTER_SEVERITY=high` for alerts only, or `FACTIONOS_ADAPTER_SEVERITY=high,medium,low` for a noisy stream.

## Throttling And Delivery

`FACTIONOS_ADAPTER_MIN_INTERVAL_MS` defaults to `8000` and applies per severity bucket. Posts are not persisted. If a destination rejects or rate-limits a post, the adapter logs the failure and moves on; the web UI and local archive remain the canonical record.

Webhook requests abort after `FACTIONOS_WEBHOOK_TIMEOUT_MS`, which defaults to `5000`.

## Generic Webhook Payloads

Use the webhook adapter for HTTPS endpoints that accept JSON, such as ntfy, custom Slack incoming hooks, serverless functions, or internal alert routers.

```bash
FACTIONOS_WS_URL=ws://localhost:2468/ \
FACTIONOS_WEBHOOK_URL=https://example.invalid/factionos-alerts \
npm run webhook
```

`FACTIONOS_WEBHOOK_PAYLOAD_SHAPE` supports two shapes:

* `compact` (default): `{ severity, title, text, emittedAt }`.
* `full` (explicit opt-in): `{ source, version, severity, title, text, emittedAt, event }`.

`full` passes through the raw FactionOS event and can expose prompts, paths, cwd, command previews, summaries, or future event fields. Use it only for reviewed internal systems that are allowed to receive raw local event data. Discord, Telegram, and compact generic webhook payloads receive formatter output only; the formatter redacts common local paths, shell command previews, webhook URLs, bot tokens, bearer values, and configured auth-header values.

## Auth Header

Set `FACTIONOS_WEBHOOK_AUTH_HEADER_NAME` and `FACTIONOS_WEBHOOK_AUTH_HEADER_VALUE` together to inject one header. The adapter does not bake in vendor-specific auth schemes. Examples include:

* `Authorization: Basic <value>`
* `Authorization: Bearer <value>`
* `X-Api-Key: <value>`

Webhook URLs and auth material should never be pasted into logs or docs. The adapter redacts the webhook URL in startup logs.

## Adding A New Adapter

1. Create `src/<name>/sender.ts` exporting `sendTo<Name>(cfg, msg)`.
2. Create `src/<name>/run.ts` modeled on `src/discord/run.ts`.
3. Add a `<NAME>_*` block to `.env.example` and a reader in `src/shared/config.ts`.
4. Register it in the dispatcher in `src/index.ts`.

The bridge, formatter, throttle, and config layers are intentionally reusable.

## Boundaries

* Outbound only. Do not add inbound chat commands without a new permission and audit model.
* Inbound channel/webhook intake, when enabled by the local server, belongs to server routes such as `/webhooks/generic`, `/webhooks/github`, and `/channels/:provider/pair`, not adapter bridge processes.
* Best effort. Do not use adapters as the system of record.
* External payloads should be treated as potentially sensitive developer data.
* Core local FactionOS workflows do not require adapters.
* Future Phase 03 orchestration events must preserve the outbound-only boundary. Compact formatter output should remain the default, and full raw webhook payloads require explicit internal review because they can expose queue, lineage, action, prompt, path, command, or transcript fields.

## Phase 07 Hosted Payload Boundary

Adapters remain optional outbound bridges, not analytics collectors, public replay hosts, hosted diagnostics, inbound command channels, or systems of record. Phase 07 Session 01 keeps compact payloads as the default and treats `FACTIONOS_WEBHOOK_PAYLOAD_SHAPE=full` as an explicit internal-only risk because it can include raw local event fields.

Adapter config values such as webhook URLs, bot tokens, auth headers, bearer values, and destination identifiers are server-side or process-local secrets. They must not be copied into browser config, docs examples, logs, diagnostics, replay fragments, exports, archives, analytics payloads, or public demo code.


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://faction-os.gitbook.io/faction-os-docs/apps/adapters/readme_adapters.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
