Skip to main content
Formation can create a distinct Slack app for each agent, configure its permissions and events URL, upload its avatar, and collect its bot credentials through Slack OAuth. The manual connection flow remains available.

Once per Formation instance

  1. Configure MESH_AGENT_MASTER_KEY and a stable, publicly reachable HTTPS PUBLIC_URL. Automatic setup requires an HTTPS origin without a path. Formation uses HTTP Events API delivery; no Socket Mode app token is needed.
  2. In Slack’s Your Apps page, find Your App Configuration Tokens and generate a configuration token for the intended workspace. The Slack account must have permission to create apps. Workspace app-approval policies still apply.
  3. In Formation Settings → Slack app provisioning, paste the refresh token. Formation rotates it immediately, stores the resulting access/refresh pair encrypted, and refreshes it while the server runs. This credential belongs to a Slack user and workspace; it is not a universal Slack administrator key.
A hosting control plane can perform step 3 instead, with its management credential: PUT /api/management/slack-provisioning with the refresh token, which is write-only and retry-safe, plus a redacted status read and a disconnect (capability slack.provisioning; see the operator API). Either way the settings page and the status report the connection’s health: ok, refresh_failing (Slack refused the last refresh; the current access token keeps working until it expires and Formation keeps retrying) or expired (setup fails until a refresh succeeds or a new refresh token is connected), with Slack’s error code and when it happened. The first version supports one current provisioning workspace per Formation instance. Replacing that connection changes the workspace used for new setup. Existing bot installations continue working. To update an app created in a previous workspace, reconnect provisioning for that workspace.

Creating an agent

  1. Name the agent and use instance model defaults or configure a supported model provider, then complete memory setup.
  2. Describe what the agent should do, then generate or write its profile. Review and edit that profile before creating its picture. Formation selects a recommended model from the current image catalog; another model or a PNG/JPEG upload remains available. Profile-driven pictures use the editable profile shown on this screen.
  3. Choose Slack and select Create Slack app. Formation creates the app, saves its credentials, registers a signed events URL, configures permissions and OAuth, and attempts to upload the picture.
  4. Select Install in Slack and approve the installation. Slack may require workspace-admin approval. Formation exchanges the authorization code on the server, validates the workspace and granted permissions, saves the bot credential, and activates the connection.
  5. Open the app in Slack and send a test message. Invite it to channels where it should participate.
Profile generation works through either text provider. Ramp Router image generation is not enabled because its image-output API has not been verified. OpenRouter image generation uses /images/models and /images; generation uses the agent’s saved provider credential and may incur provider charges. A failed generation does not block manual editing or upload. Automatic picture updates may follow profile generation or a saved profile change. Uploaded pictures and pictures saved before provenance tracking are preserved; choose Generate picture explicitly to replace them. Automatic generation never runs on every keystroke. Only this agent’s name and the submitted editable profile are sent for the picture; Formation does not add memories, conversations, connected accounts, or secrets. A wizard draft URL survives reload. Provisioning progress is stored on the server, so refreshing or resuming a draft does not create another Slack app. Credentials are never persisted in browser storage.

Delegated setup from a hosted console

A hosted control plane can run steps 3–4 for a console user who has no Formation session, once the instance has a provisioning grant (above). The management capabilities document advertises slack.delegated_setup with a live capability_status entry that is ready only while a working grant is connected and PUBLIC_URL is valid; otherwise its reason says what is missing (provisioning_not_configured, provisioning_expired, …). It requests a single-use, ten-minute delegation for one agent with its management credential, and the user’s browser follows the returned link to Slack and back to the console. The OAuth state is still single use, expires after ten minutes, and is bound to the browser that opened the link (by a host-only cookie for that attempt, not a session); the workspace, app, bot user and scopes are checked exactly as above. Cookies are never shared across domains and no administrator session is created. Each agent keeps its own Slack app and bot user. See the operator API for the contract and outcome codes. Readiness reports connected only after Slack has delivered a signed request to the install (the events URL verification for an automatically created app, or the first signed event); a saved, auth-checked credential alone is credentials_saved. The first accepted human message and first delivered reply are recorded as timestamps for first-conversation proof, never with content.

Recovery and maintenance

  • Creation outcome uncertain: Formation will not retry app creation blindly. Inspect the apps in Slack and recover that app using the manual connection option. The creation intent remains blocked rather than risking duplicates. Automated orphan reconciliation/deletion is not implemented.
  • Configuration failure: resume setup against the saved app ID. Rate-limit errors expose Slack’s retry delay; retry after that interval.
  • Picture upload failure: installation remains available. Download the avatar and upload it through Slack’s app settings, or retry Sync profile picture.
  • Expired/cancelled OAuth: return to the saved setup and start a new installation attempt. OAuth state is single-use, user-bound, bound to the dashboard session (or, for delegated setup, to the browser that opened the delegation link), and expires after ten minutes.
  • Saved installation awaiting activation: use Activate connection. The bot credential has already been saved; another OAuth approval is unnecessary.
  • Changed hostname or configuration: open the connection’s Manage automatic Slack setup and picture link and select Update Slack configuration. This updates the existing app’s event and OAuth callback URLs using the current PUBLIC_URL.
  • Changed avatar: use Sync profile picture on each managed Slack connection. Uploading/generating a new Formation avatar marks app icons pending; it does not silently publish the new picture to every connected app.
  • Revoked or expired provisioning grant: the settings page (and the management status) shows refresh_failing or expired with Slack’s error code. Reconnect it in Settings, or have the control plane connect a new refresh token. Disconnecting provisioning removes its Formation credential; it does not uninstall existing apps or revoke their bot tokens.
Formation’s existing single-replica deployment model still applies. The database prevents competing creation attempts and serializes configuration-token rotation, but runtime registry reload is local to the serving process.

Implementation and verification

Migration 0042 adds durable Slack app intents, OAuth attempts and bounded PNG avatar storage. App client/signing credentials and OAuth bot credentials are encrypted with the existing secret store. Pending URL verification checks Slack’s timestamped HMAC before the app is installed; active events must also match the recorded app and workspace before entering the existing ingress. Migration 20261021023239 records avatar provenance and a monotonically increasing revision. Existing rows become unknown, which automatic updates preserve. Uploads become uploaded; generated pictures become generated; provisioning fallbacks become default. Conditional database writes prevent an old generation from overwriting an upload or a newer picture, including after client cancellation. The profile and picture API contract defines the live catalog recommendation, edited-profile input, avatar state, provenance, revision checks, and recovery responses for programmatic callers. Automated checks cover encrypted persistence, concurrent token rotation, interrupted/ambiguous app creation, safe retries, pending signed challenges, OAuth session/workspace/scope validation and replay prevention. Browser coverage uses the real Go server and PostgreSQL with local Slack/OpenRouter fakes, and exercises both manual and automatic onboarding, identity generation, reload/resume, OAuth activation, configuration repair and expired authorization. Automated tests use local provider fakes; they do not certify your live Slack workspace or model account. Validate app creation, icon upload, URL verification, workspace approval and a real DM when configuring a deployment. A manual icon upload remains available when automatic upload fails. This implementation does not include manager-app enrollment, unattended child-app installation, public-channel discovery/joining, uninstall/revocation event handling, automatic orphan cleanup, a dedicated provisioning audit UI, or bulk hostname repair.

Troubleshooting the configuration connection

An expired access token on Slack’s App Configuration Tokens page does not require pasting that access token into Formation. Formation uses the refresh token to obtain a new pair through tooling.tokens.rotate. If connecting returns Slack: invalid_arguments on an older build, upgrade to the fix that sends rotation requests as application/x-www-form-urlencoded. Slack’s live endpoint ignores JSON rotation bodies and reports a missing refresh_token, even though its reference lists JSON support. A rejected request of this kind does not rotate the token; retry with the refresh token after upgrading. If Slack instead returns invalid_refresh_token, generate a new configuration token pair in Slack and paste its refresh token. Unexpected provisioning failures (HTTP 5xx responses) now reach the configured error tracker with component admin.api, the route pattern, and a classified error code, including slack_invalid_arguments. Tokens, request bodies, URLs, and raw provider/database errors are excluded. Expected OAuth and setup-state conflicts are not reported as failures.