Use Avibe

SkillProductivity

Safely inspect and modify local Avibe configuration, routing, runtime settings, watches, scheduled tasks, Avibe Cloud remote access, and operational state.

Available today. Use it from your connected AI after setup.

Connect ahel once, and every AI you use reads what you have installed.

Then ask your AI: use the Use Avibe skill

What this skill tells your AI

The instructions your AI receives, as published by avibe-bot/avibe in skills/use-avibe/SKILL.md and read by ahel’s review.

Use this skill when the user asks you to configure, repair, explain, or operate a local Avibe installation.

Typical requests include:

  • enable a Slack, Discord, Telegram, Lark/Feishu, or WeChat scope
  • route one channel or DM user to OpenCode, Claude, or Codex
  • set a working directory for a channel or DM user
  • choose a backend model, subagent, or reasoning level
  • show or hide intermediate message types
  • configure an outbound proxy (proxy_url) for an IM platform that cannot reach its API directly
  • pair, start, stop, or inspect Avibe Cloud remote Web UI access
  • create, update, inspect, pause, resume, or remove a managed background watch with vibe watch
  • create, inspect, run, pause, resume, or remove a scheduled task with vibe task
  • run a one-shot Agent job with vibe agent run, including async background runs
  • inspect or cancel concrete Agent Run records with vibe runs
  • check or apply Avibe updates (vibe check-update, vibe upgrade)
  • inspect logs, run doctor, check service status, or explain where Avibe stores state
  • decide whether a requested change belongs in Avibe config or in the host backend's own config

Follow this skill as an operations playbook for agents, not as end-user marketing copy.

Core Rules

  1. Prefer the Web UI API for Avibe configuration changes. Do not hand-edit config files for routine work.
  2. Read current API state before mutating. Merge the user's requested change into the current payload.
  3. Preserve unrelated scopes, platforms, users, and secrets.
  4. Treat secrets as opaque. Do not print, invent, rotate, or overwrite tokens unless the user explicitly provides replacements.
  5. Use the smallest viable API call and verify by reading back the API response.
  6. For POST /settings, preserve every existing channel for that platform; the endpoint replaces the platform's channel map.
  7. For POST /api/users, merge each edited user with its current user payload first; missing user fields are not a patch.
  8. Make every persistent-state change through the Web UI API or the vibe CLI. Avibe's internal storage is opaque — do not read, query, or hand-edit it.
  9. POST /config persists the new payload but does not restart running platform adapters by itself. When the change is platform credentials, proxy_url, or other transport-level settings, plan an explicit restart afterwards; prefer the delayed CLI form (vibe restart --delay-seconds 60) when triggering it from inside an active conversation. The only credential save that restarts on its own is the WeChat QR-login completion through POST /wechat/qr_login/poll.
  10. Do not restart the service by default. Use POST /doctor, GET /status, and read-back checks first.
  11. Only start, stop, restart, or reload Avibe when the user explicitly asks or when a change cannot take effect otherwise; explain why before doing it.
  12. If an agent must restart Avibe from an active conversation, use vibe restart --delay-seconds 60 so the current session can receive the reply before the restart lands.
  13. Tell the user whether the change is global or scope-specific.

API First Workflow

Use this order when changing Avibe configuration:

  1. Determine the Web UI base URL.
    • Default is http://127.0.0.1:5123.
    • If the user has a custom UI host or port (from ui.setup_host / ui.setup_port), use that exact origin.
    • When Avibe Cloud remote access is active, the public origin (e.g. https://<slug>.avibe.bot) also speaks the same API and requires OIDC session cookies — prefer the local origin from the host running Avibe.
    • Check liveness with GET /health or GET /status.
  2. Decide whether the request belongs in:
    • POST /config for global defaults, platform credentials, runtime config, agent defaults, UI config, remote-access provider settings, update policy, or global display toggles
    • POST /settings for channel-level routing, working directory, visibility, enablement, and mention policy
    • /api/users and /api/bind-codes for DM user binding and user-scope settings
    • /remote-access/* for Avibe Cloud pairing and tunnel control
    • host backend config instead of Avibe when the request is OpenCode, Claude Code, or Codex native behavior
  3. Fetch the current state from the matching GET endpoint.
  4. Merge the requested change in memory.
  5. Send the mutating request through the Web UI API with CSRF protection.
  6. Read back the changed resource and verify the effective payload.
  7. Run POST /doctor only when the change affects runtime health, platform credentials, or backend availability.
  8. Report the changed scope or global keys and whether a restart was avoided or still required.

Calling the Web UI API

Mutating API calls require:

  • same-origin Origin or Referer header
  • CSRF cookie named vibe_csrf_token
  • matching X-Vibe-CSRF-Token header

Use this local curl pattern:

BASE="http://127.0.0.1:5123"
COOKIE_JAR="$(mktemp)"
CSRF="$(
  curl -fsS -c "$COOKIE_JAR" "$BASE/api/csrf-token" \
    | python3 -c 'import json,sys; print(json.load(sys.stdin)["csrf_token"])'
)"

curl -fsS -b "$COOKIE_JAR" -c "$COOKIE_JAR" \
  -H "Origin: $BASE" \
  -H "X-Vibe-CSRF-Token: $CSRF" \
  -H "Content-Type: application/json" \
  -X POST "$BASE/doctor" \
  --data '{}'

For DELETE, use the same cookie jar, Origin, and CSRF header.

When the Web UI is served through Avibe Cloud, the same calls require an authenticated OIDC session cookie issued by /auth/callback. Prefer hitting 127.0.0.1:5123 directly from the local machine for maintenance work.

Do not log full request bodies when they contain tokens or secrets.

Reusable local API helper

For multi-step maintenance, use the bundled helper at scripts/vibe_api.py instead of hand-writing curl commands. The helper handles CSRF, same-origin headers, cookies, JSON encoding, and readable error output.

Resolve paths relative to this skill directory. If the skill is installed at skills/use-avibe, run:

Usage examples:

export VIBE_UI_BASE="http://127.0.0.1:5123"

python3 skills/use-avibe/scripts/vibe_api.py GET /health
python3 skills/use-avibe/scripts/vibe_api.py GET '/settings?platform=slack'
python3 skills/use-avibe/scripts/vibe_api.py POST /doctor '{}'
python3 skills/use-avibe/scripts/vibe_api.py POST /config '{"show_duration":true}'
python3 skills/use-avibe/scripts/vibe_api.py DELETE '/api/users/U123?platform=slack'

Payload can be passed as inline JSON, as @payload.json, or as - to read JSON from stdin.

For scope updates, still fetch and merge first:

API_HELPER="skills/use-avibe/scripts/vibe_api.py"

python3 "$API_HELPER" GET '/settings?platform=slack' > /tmp/slack_settings.json
python3 - <<'PY'
import json
from pathlib import Path

settings = json.loads(Path("/tmp/slack_settings.json").read_text())
channels = settings.get("channels") or {}
channels["C123"] = {
    **channels.get("C123", {}),
    "enabled": True,
    "show_message_types": channels.get("C123", {}).get("show_message_types") or ["assistant"],
    "custom_cwd": channels.get("C123", {}).get("custom_cwd"),
    "require_mention": channels.get("C123", {}).get("require_mention"),
    "routing": {
        **(channels.get("C123", {}).get("routing") or {}),
        "agent_name": "codex",
        "model": "gpt-5.4",
        "reasoning_effort": "high",
        "codex_model": "gpt-5.4",
        "codex_reasoning_effort": "high",
    },
}
Path("/tmp/slack_payload.json").write_text(json.dumps({"platform": "slack", "channels": channels}))
PY
python3 "$API_HELPER" POST /settings @/tmp/slack_payload.json
python3 "$API_HELPER" GET '/settings?platform=slack'

Runtime Layout

Avibe stores runtime data under ~/.avibe/ by default, or under AVIBE_HOME when that env var is set. Existing default ~/.vibe_remote/ homes may be migrated to ~/.avibe/ with ~/.vibe_remote kept as a back-symlink. The only paths an agent normally needs:

  • ~/.avibe/config/config.json — global config; mutate through POST /config, not by editing the file
  • ~/.avibe/logs/vibe_remote.log — main application log; read via POST /logs
  • ~/.avibe/screenshots/ — default output directory for vibe screenshot
  • ~/.avibe/state/user_preferences.md — shared long-term preference file (safe to read and update)

Agent harness state is managed through vibe agent run, vibe task, vibe watch, and vibe runs (or their API endpoints), not by editing persistence files. Everything else under state/ and runtime/ is internal — treat it as opaque.

API Endpoint Reference

Health and inspection

  • GET /health
    • returns {"status":"ok"} when the Web UI server is reachable
  • GET /status
    • returns runtime status, running state, PID metadata, and last action
  • GET /doctor
    • reads the latest persisted doctor result
  • POST /doctor
    • runs doctor immediately and returns the result
  • POST /logs
    • payload: {"lines": 500, "source": "service"}
    • source can be service or another source listed in the response; use all for aggregated logs
  • GET /version
    • returns current version and update metadata
  • GET /api/csrf-token
    • issues the vibe_csrf_token cookie and returns the matching token value for X-Vibe-CSRF-Token
  • GET /platforms
    • returns the static catalog of supported IM platforms only (id, config_key, title/description i18n keys, credential field names, capabilities). It does not include enablement or credential-presence state — fetch /config to see which platforms are enabled and whether credentials are configured.

Global config

  • GET /config
    • returns the current V2 config payload
  • POST /config
    • accepts a partial object, deep-merges it with current config, validates it through V2Config.from_payload, then persists it
    • use for platform credentials, enabled platforms, primary platform, runtime defaults, agent defaults, UI config, remote-access provider settings, update policy, and global toggles
    • the handler only persists and (for remote_access) reconciles the cloudflared tunnel; running platform adapters keep using their previous credentials and transport until a restart. Plan a vibe restart --delay-seconds 60 after any credential, proxy_url, or transport-level change.

Important config payload shape:

{
  "platform": "slack",
  "platforms": {
    "enabled": ["slack", "discord", "telegram", "lark", "wechat"],
    "primary": "slack"
  },
  "mode": "self_host",
  "version": "v2",
  "slack": {
    "bot_token": "xoxb-...",
    "app_token": "xapp-...",
    "signing_secret": "...",
    "team_id": "T...",
    "team_name": "...",
    "app_id": "A...",
    "require_mention": false,
    "disable_link_unfurl": false,
    "proxy_url": null
  },
  "discord": {
    "bot_token": "...",
    "application_id": "...",
    "require_mention": false,
    "thread_auto_archive_minutes": 10080,
    "guild_allowlist": null,
    "guild_denylist": null,
    "proxy_url": null
  },
  "telegram": {
    "bot_token": "123:abc",
    "require_mention": true,
    "forum_auto_topic": true,
    "use_webhook": false,
    "webhook_url": null,
    "webhook_secret_token": null,
    "allowed_chat_ids": null,
    "allowed_user_ids": null,
    "proxy_url": null
  },
  "lark": {
    "app_id": "...",
    "app_secret": "...",
    "require_mention": false,
    "domain": "feishu",
    "proxy_url": null
  },
  "wechat": {
    "bot_token": "...",
    "base_url": "https://ilinkai.weixin.qq.com",
    "cdn_base_url": "https://novac2c.cdn.weixin.qq.com/c2c",
    "require_mention": false,
    "proxy_url": null
  },
  "runtime": {
    "default_cwd": "/path/to/workdir",
    "log_level": "INFO"
  },
  "agents": {
    "opencode": {
      "enabled": true,
      "cli_path": "opencode",
      "default_agent": null,
      "default_reasoning_effort": null,
      "error_retry_limit": 1
    },
    "claude": {
      "enabled": true,
      "cli_path": "claude",
      "idle_timeout_seconds": 600
    },
    "codex": {
      "enabled": true,
      "cli_path": "codex",
      "idle_timeout_seconds": 600
    }
  },
  "ui": {
    "setup_host": "127.0.0.1",
    "setup_port": 5123,
    "open_browser": true
  },
  "remote_access": {
    "provider": "vibe_cloud",
    "vibe_cloud": {
      "enabled": false,
      "backend_url": "https://avibe.bot",
      "public_url": "",
      "instance_id": "",
      "client_id": "",
      "issuer": "",
      "authorization_endpoint": "",
      "token_endpoint": "",
      "jwks_uri": "",
      "redirect_uri": "",
      "tunnel_token": "",
      "instance_secret": "",
      "session_secret": "",
      "cloudflared_path": "",
      "transport_protocol": "auto",
      "auto_recovery": true,
      "optimization_profile": "balanced",
      "edge_ip_version": "4",
      "edge_bind_address": "",
      "dev_login_hint": ""
    }
  },
  "update": {
    "auto_update": true,
    "check_interval_minutes": 60,
    "idle_minutes": 30,
    "notify_admins": true
  },
  "ack_mode": "typing",
  "language": "en",
  "show_duration": false,
  "include_time_info": true,
  "include_user_info": true,
  "reply_enhancements": true
}

Discord server access belongs to /settings, not /config. Store enabled servers under guilds, next to channel settings:

{
  "platform": "discord",
  "guilds": {
    "900740769198006293": { "enabled": true }
  },
  "channels": {
    "1067738479234138202": { "enabled": true }
  }
}

When switching the active platform, update platforms.primary and make sure platforms.enabled contains the new primary. Keep the legacy platform field aligned for readability, but platforms.primary is the real multi-platform source of truth.

Per-platform fields worth knowing about:

  • every platform inherits proxy_url from the shared BaseIMConfig. Set it when the host machine cannot reach the upstream API directly. Accepts standard HTTP/HTTPS proxy URLs and any socks*:// URL (socks4, socks4a, socks5, socks5h). SOCKS variants route through aiohttp_socks.
  • slack.disable_link_unfurl suppresses link previews when posting messages.
  • discord.thread_auto_archive_minutes must be one of 60, 1440, 4320, or 10080.
  • discord.guild_allowlist / guild_denylist are legacy input lists; current runtime server access lives in /settings under guilds.
  • telegram.forum_auto_topic enables automatic topic creation in forum chats; use_webhook plus webhook_url / webhook_secret_token switches Telegram delivery to the webhook transport.
  • telegram.allowed_chat_ids / allowed_user_ids restrict which chats and users Telegram will respond to.
  • wechat.cdn_base_url controls the CDN host used for fetching WeChat media; the default novac2c.cdn.weixin.qq.com is the official c2c CDN.
  • update.auto_update, check_interval_minutes, and idle_minutes control unattended upgrades; notify_admins posts the upgrade announcement to bound admins.
  • ui.setup_host, setup_port, and open_browser configure the local Web UI server; changing host or port requires POST /ui/reload.

Secret-bearing config fields that you should not print:

  • slack.bot_token
  • slack.app_token
  • slack.signing_secret
  • discord.bot_token
  • telegram.bot_token
  • telegram.webhook_secret_token
  • lark.app_id (treat as a sensitive identifier)
  • lark.app_secret
  • wechat.bot_token
  • gateway.workspace_token
  • gateway.client_secret
  • remote_access.vibe_cloud.tunnel_token
  • remote_access.vibe_cloud.instance_secret
  • remote_access.vibe_cloud.session_secret
  • remote_access.vibe_cloud.client_id
  • any proxy_url value that embeds credentials such as user:pass@host

Channel settings

  • GET /settings?platform=<platform>
    • returns channel settings, user settings, and bind codes for one platform
  • POST /settings
    • payload: {"platform": "<platform>", "channels": {...}}
    • validates message visibility and routing, normalizes Claude reasoning, persists the full channel map for that platform

Important: POST /settings replaces the entire channels map for the selected platform. To change one channel:

  1. GET /settings?platform=<platform>
  2. copy response.channels
  3. merge or add one channel entry
  4. POST /settings with the full merged channels object
  5. GET /settings?platform=<platform> again and verify

Channel entry shape:

{
  "enabled": true,
  "show_message_types": ["assistant"],
  "custom_cwd": "/path/to/repo",
  "require_mention": null,
  "require_bind": null,
  "routing": {
    "agent_name": "codex",
    "model": "gpt-5.4",
    "reasoning_effort": "high",
    "opencode_agent": null,
    "opencode_model": null,
    "opencode_reasoning_effort": null,
    "claude_agent": null,
    "claude_model": null,
    "claude_reasoning_effort": null,
    "codex_agent": "reviewer",
    "codex_model": "gpt-5.4",
    "codex_reasoning_effort": "high"
  }
}

Field meanings:

  • enabled: whether this channel is allowed to use Avibe
  • show_message_types: visible intermediate messages; allowed values are system, assistant, toolcall
  • custom_cwd: scope-level working directory override; empty string or null means use global default
  • require_mention: null inherits the platform default, true requires mention, false disables mention gating for that channel
  • require_bind: null/false lets any channel member use the bot (current default); true gates the channel to bound users only — messages from unbound senders are silently ignored (no denial reply), while the bot's own replies stay visible to everyone. Enforced in the shared auth pipeline, so it applies on every platform. Bind is platform-wide, so require_bind means "is this sender a bound user", not a per-channel allowlist.
  • routing.agent_name: Vibe Agent name for this scope, or null to inherit the default Agent
  • routing.model: canonical scope-level model override for the selected Agent backend
  • routing.reasoning_effort: canonical scope-level reasoning override for the selected Agent backend
  • routing.<backend>_agent: backend-specific subagent
  • routing.<backend>_model / routing.<backend>_reasoning_effort: legacy aliases accepted on input and derived on read-back; do not treat them as independent state

DM users and bind codes

  • GET /api/users?platform=<platform>
    • returns bound DM users for one platform
  • POST /api/users
    • payload: {"platform": "<platform>", "users": {...}}
    • merges included users into existing users and preserves each existing user's dm_chat_id
  • POST /api/users/<user_id>/admin
    • payload: {"platform": "<platform>", "is_admin": true}
  • DELETE /api/users/<user_id>?platform=<platform>
    • removes a bound user; this is the reliable way to revoke DM access
  • GET /api/bind-codes
    • returns all bind codes
  • POST /api/bind-codes
    • payload: {"type": "one_time"} or {"type": "expiring", "expires_at": "2026-04-18"}
  • DELETE /api/bind-codes/<code>
    • deactivates a bind code
  • GET /api/setup/first-bind-code
    • returns an existing valid setup bind code or creates a new one-time code

Important: user updates are not field patches. Before changing a user's routing, cwd, visibility, or enabled flag, read the current user object and send the merged full user entry.

User entry shape:

{
  "display_name": "Alice",
  "is_admin": false,
  "bound_at": "2026-03-20T12:34:56+00:00",
  "enabled": true,
  "show_message_types": ["assistant"],
  "custom_cwd": "/path/to/repo",
  "routing": {
    "agent_name": "claude",
    "model": "claude-sonnet-4-6",
    "reasoning_effort": "high",
    "opencode_agent": null,
    "opencode_model": null,
    "opencode_reasoning_effort": null,
    "claude_agent": "reviewer",
    "claude_model": "claude-sonnet-4-6",
    "claude_reasoning_effort": "high",
    "codex_agent": null,
    "codex_model": null,
    "codex_reasoning_effort": null
  }
}

DM caveat: current DM authorization checks whether the user is bound, not whether enabled is true. If the user wants to revoke DM access, use DELETE /api/users/<user_id>?platform=<platform> instead of only setting enabled to false.

Platform discovery and validation

  • GET /slack/manifest
    • returns Slack app manifest JSON for setup
  • POST /slack/auth_test
    • payload: {"bot_token": "xoxb-..."}
  • POST /slack/channels
    • payload: {"bot_token": "xoxb-...", "browse_all": false}
  • POST /discord/auth_test
    • payload: {"bot_token": "..."}
  • POST /discord/guilds
    • payload: {"bot_token": "..."}
  • POST /discord/channels
    • payload: {"bot_token": "...", "guild_id": "..."}
  • POST /telegram/auth_test
    • payload: {"bot_token": "123:abc"}
  • POST /telegram/chats
    • payload: {"include_private": false}
  • POST /lark/auth_test
    • payload: {"app_id": "...", "app_secret": "...", "domain": "feishu"}
  • POST /lark/chats
    • payload: {"app_id": "...", "app_secret": "...", "domain": "feishu"}
  • POST /lark/temp_ws/start
    • payload: {"app_id": "...", "app_secret": "...", "domain": "feishu"}
  • POST /lark/temp_ws/stop
    • payload: {}
  • POST /wechat/qr_login/start
    • payload: {"base_url": "https://ilinkai.weixin.qq.com"} or {}
  • POST /wechat/qr_login/poll
    • payload: {"session_key": "..."}

WeChat QR login is special: when login is confirmed and a token is returned, the API auto-binds the WeChat user and schedules an internal service restart so the new token can take effect. Do not add an extra restart unless the user asks.

Remote access (Avibe Cloud)

These endpoints drive the managed avibe.bot tunnel that exposes the local Web UI to other devices. They are paired with the remote_access.vibe_cloud block under /config.

Shortened here. Read the whole file on GitHub.

Signals

GitHub stars
505
Forks
79
Last commit
Sep 2026
Advanced
Catalog kind
skill
Gateway key
use-avibe
Source
github.com/avibe-bot/avibe