baturyilmaz/agent-office
Slack for AI Agents. Contribute to baturyilmaz/agent-office development by creating an account on GitHub.
0 stars · 0 forks
README
agent-office Multi-agent workspace manager built on Pi. Orchestrates AI coding agents — similar to Claude Code or OpenClaw — with tick-based scheduling, priority queues, inbox IPC, cross-agent file access, watchdog monitoring, proactive cron jobs, optional Docker sandbox isolation, and declarative YAML configuration.
agent-office.mp4
Get Started Try one of these examples to get up and running quickly. Set env vars in the project root .env (not inside Docker — the host forwards them to containers). Basic team — PM, coder, and reviewer (uses GitHub Copilot OAuth, no API keys): pnpm install cp -r examples/basic-team/ ~/.agent-office/offices/basic-team/ pnpm dev oauth login github-copilot --office basic-team pnpm dev start --office basic-team --sandbox docker OpenServ team — idea scout, team lead, agent dev, and token launcher: pnpm install cp .env.example .env mkdir -p ~/.agent-office/offices/openserv-team cp examples/openserv-team/office.yaml ~/.agent-office/offices/openserv-team/office.yaml pnpm dev start --office openserv-team --sandbox docker OPENAI_API_KEY= WALLET_PRIVATE_KEY= # EVM wallet key for openserv-labs/skills agents Feature team — task-driven development with Kanban board: cp -r examples/feature-team/ ~/.agent-office/offices/feature-team/ pnpm dev start --office feature-team See examples/ for more details — each has a README describing the setup. Table of Contents
Architecture Quick Start OAuth Authentication
Supported Providers CLI Commands Using OAuth in office.yaml Web UI Auth Selector
Multi-Office Architecture
Creating an Office Office Configuration Heartbeat Permissions Tool Policy Hierarchy Auto-Sync Reload Cron Jobs Office-Level Cron Agent Cron Tools Task Management Migration from agents.yaml
Sandbox Modes
In-Process Mode Docker Sandbox Mode
Commands
Hire Options CLI Flags Execution Surfaces REST API Endpoints
Agent Tools
list_agents message_agent message_user post_channel read_agent_file authenticated_fetch cron_add cron_remove cron_list read_skill skill_search skill_install skill_remove skill_create task_create task_update task_list task_get task_delete Tool Architecture Prompt System
Concepts
Tick-Based Scheduler Priority Levels Workspace Sandboxing Skills Watchdog Message Persistence
Prompt Inspection Cost Tracking Web UI End-to-End Examples Project Structure Dependencies Development
Architecture
graph TD YAML[office.yaml] --> WS CLI[CLI + Web UI] --> WS[Workspace]
WS --> SCH[Scheduler\ntick loop] WS --> BUS[MessageBus\ninboxes] WS --> WD[Watchdog\nheartbeat] WS --> CRON[CronService\nscheduled jobs] WS --> TS[TaskService\nKanban board]
WS -->|in-process| A[Agent A\nPi · tools · skills] WS -->|in-process| B[Agent B\nPi · tools · skills]
WS -->|Docker sandbox| HA[Host API\nHTTP :13000] HA <-->|HTTP| SA[Sandbox A\nDocker · Pi · proxy tools] HA <-->|HTTP| SB[Sandbox B\nDocker · Pi · proxy tools]
BUS --> A BUS --> B BUS --> HA
Loading
Core flow: office.yaml (auto-spawn) / CLI / Web UI / Cron / Agent cron tools / Task notifications -> Workspace -> Scheduler tick -> drain inbox -> dispatch to Pi Agent -> agent runs tools -> response streamed to UI. Each agent is a full Pi coding agent with its own filesystem workspace, skills, and injected tools (message_user, post_channel, message_agent, list_agents, read_agent_file, authenticated_fetch, cron_add, cron_remove, cron_list, task_create, task_update, task_list, task_get, task_delete, read_skill, skill_search, skill_install, skill_remove, skill_create). The scheduler runs a tick loop that serves agents by priority, one message per tick per agent, non-blocking. Agents can run in-process (default) or inside Docker containers for full process-level isolation. Quick Start pnpm install
Configure .env
cp .env.example .env # then fill in your keysCreate an office
pnpm dev office create my-teamStart (Web UI auto-starts)
pnpm dev start --office my-teamStart with Docker sandbox isolation
pnpm dev start --office my-team --sandbox docker Create a .env file with your provider API keys. Each model requires its corresponding provider key:Model API Keys (required for agents using these models)
OPENAI_API_KEY=sk-... # For OpenAI models (gpt-4o, etc.) ANTHROPIC_API_KEY=sk-... # For Anthropic models (Claude, etc.) GEMINI_API_KEY=... # For Google Gemini models XAI_API_KEY=... # For xAI Grok modelsOptional: Custom secret refs for office.yaml agents
MY_GH_TOKEN=ghp_... # Host env vars for authenticated_fetch secrets
Authentication: Each model needs credentials. You can use either API keys (.env) or OAuth:API keys — set in .env (e.g. OPENAI_API_KEY=sk-...). Required when the model's provider has no OAuth credentials. OAuth — authenticate via provider CLIs before starting. OAuth tokens auto-refresh and don't require .env keys.
Option A: API keys in .env
echo "ANTHROPIC_API_KEY=sk-..." >> .envOption B: OAuth login (requires provider CLI installed)
pnpm dev oauth login anthropic --office my-team pnpm dev oauth list --office my-team When both OAuth credentials and an API key exist for a provider, you can switch between them per-agent in the Web UI. See OAuth Authentication for details. See the Dynamic Model Discovery section below for how to browse available models and their requirements in the Web UI. OAuth Authentication As an alternative to API keys in .env, agents can authenticate with model providers via OAuth. This uses the provider's own CLI login flow — the agent-office CLI orchestrates the browser-based OAuth handshake and stores credentials per office. Supported ProvidersProvider ID Name Flow Type Requires
anthropic Anthropic Code paste Anthropic CLI
openai-codex OpenAI Callback server OpenAI Codex CLI
github-copilot GitHub Copilot Code paste GitHub Copilot CLI
google-gemini-cli Google Gemini CLI Callback server Gemini CLI
google-antigravity Antigravity Callback server Antigravity CLI
Code paste providers open a browser URL and prompt you to paste back an auth code. Callback server providers start a local HTTP server and complete the flow automatically. CLI Commands
Login — interactive OAuth flow (opens browser)
pnpm dev oauth login <provider> --office <id>List — show all providers and credential status
pnpm dev oauth list --office <id>Logout — remove stored credentials
pnpm dev oauth logout <provider> --office <id> Example session: $ pnpm dev oauth login anthropic --office my-team [oauth] Logging in to Anthropic... [oauth] Open this URL to authenticate: https://console.anthropic.com/oauth/... Paste the authorization code: ** [oauth] Credentials saved for Anthropic.$ pnpm dev oauth list --office my-team ✓ anthropic Anthropic ✗ openai-codex OpenAI ✗ github-copilot GitHub Copilot ✗ google-gemini-cli Google Gemini CLI ✗ google-antigravity Antigravity
Login: pnpm dev oauth login <provider> --office my-team Logout: pnpm dev oauth logout <provider> --office my-team Credentials are stored at ~/.agent-office/offices/<id>/oauth/<provider>.json and auto-refresh when tokens expire. Using OAuth in office.yaml Set the auth field on an agent to use OAuth instead of an API key: agents: designer: model: anthropic:claude-sonnet-4-20250514 auth: "oauth:anthropic" # use OAuth credentials reviewer: model: openai:gpt-4o auth: "oauth:openai-codex" # use OAuth credentials analyst: model: google:gemini-2.0-flash # no auth field — falls back to GEMINI_API_KEY from .env The auth field format is oauth:<provider-id>. When set, the agent uses stored OAuth credentials with automatic token refresh instead of a static API key. Web UI Auth Selector When OAuth credentials exist for an agent's model provider, the Web UI Config tab shows an Auth selector to switch between "API Key" and "OAuth" modes. The UI also displays all authenticated providers as green badges with one-click removal. The auth selector only appears when credentials are available — if no OAuth login has been done for a provider, agents use API keys by default. OAuth REST API
Method Path Description
GET /api/oauth/providers List all providers with authentication status
GET /api/oauth/status/:id Check if credentials exist for a provider
DELETE /api/oauth/:id Remove stored credentials for a provider
Multi-Office Architecture Each office represents a company or team with shared identity, env vars, and secrets. Offices live under ~/.agent-office/offices/<id>/. Creating an Office
Create with default display name (same as id)
pnpm dev office create acmeCreate with a custom display name
pnpm dev office create acme --name "Acme Corp" Office IDs must be path-safe: lowercase letters, digits, hyphens, underscores (matching [a-z0-9][a-z0-9_-]*). The display name (office.name in YAML) is free-form. Office Configuration (office.yaml) Define your office once in ~/.agent-office/offices/<id>/office.yaml and agents auto-spawn on startup.~/.agent-office/offices/acme/office.yaml
office: name: Acme Corp description: "We build AI-powered widgets" env: SHARED_API_URL: https://api.acme.com secrets: SHARED_TOKEN: ${ACME_TOKEN} cron: standup: schedule: "0 9 1-5" report_channel: general tasks: - title: "Daily standup" assignee: pmagents: designer: model: anthropic:claude-sonnet-4-20250514 priority: normal # idle | low | normal | high | critical (or 0-4) thinking: low # off | minimal | low | medium | high | xhigh description: "Frontend designer — builds HTML/CSS" prompt_inline: | You are a frontend designer specializing in responsive layouts. Focus on clean, semantic HTML and modern CSS. skills: - nichochar/web-skills auth: "oauth:anthropic" # optional — use OAuth instead of API key api_key_ref: MY_CUSTOM_KEY # optional — host env var name for model key override env: # non-sensitive, passed as Docker --env (agent overrides office) LOG_LEVEL: debug WORKSPACE_NAME: designer secrets: # sensitive, ${VAR} refs only — delivered via authenticated_fetch GITHUB_TOKEN: ${MY_GH_TOKEN} disclose_secrets: true # show secret names in system prompt (default: false) permissions: office_cron: true # allow managing office-level cron jobs
reviewer: model: openai:gpt-4.1 priority: high thinking: medium description: "Code reviewer" Office-level env and secrets are inherited by all agents. Agent-level values override office-level. All agent fields are optional. Agents are spawned sequentially in declaration order; if one fails, the rest still start. Model availability depends on your provider account — replace the model value with your preferred provider:model-id if the default is unavailable.
Field Type Default Description
model string anthropic:claude-sonnet-4-20250514 provider:model-id
priority string | number normal Priority name or 0-4
thinking string low off / minimal / low / medium / high / xhigh
description string "" Visible to other agents
prompt_inline string (none) Custom instructions (inline text, appended to base prompt)
cwd string ~/.agent-office/offices/<id>/agents/<name>/workspace Working directory
skills string[] [] GitHub sources to auto-install (owner/repo)
auth string (none — uses API key) Auth mode: oauth:<provider-id> for OAuth (see OAuth)
api_key_ref string (auto from provider) Host env var name for model API key
env map {} Non-sensitive env vars (Docker --env, supports ${VAR} refs)
secrets map {} Secret refs in ${VAR} format (delivered via authenticated_fetch)
disclose_secrets boolean false Show secret names in system prompt
cron map {} Named cron jobs (see Cron Jobs)
reports_to string (none — reports to user) Name of manager agent (see Hierarchy)
permissions map {} Agent permissions (see Permissions, Tool Policy)
prompt_mode string "full" full (all blocks) or minimal (base + identity + custom only)
on_demand_skills boolean true Advertise skill summaries; load full content on demand via read_skill
heartbeat map (none) Proactive heartbeat config (see Heartbeat)
Task tools (task_create, task_update, task_list, task_get, task_delete) are available to all in-process agents by default. Restrict access via permissions.tools.deny. See Task Management. Heartbeat Agents can run proactively via heartbeats — periodic messages that prompt agents to check for work or run maintenance without external triggers. agents: monitor: heartbeat: interval_ms: 60000 prompt: "Check for pending work and report status" active_hours: start: "09:00" end: "17:00"
Field Required Default Description
interval_ms yes — Interval in milliseconds between heartbeats
prompt no (default) Custom prompt text for heartbeat messages
active_hours no (none) Restrict heartbeats to a time window
Heartbeat messages are injected with from: "_heartbeat_" and formatted as [Heartbeat]\n<prompt>. Busy agents (status running) are skipped. Permissions The permissions field controls which privileged operations an agent may perform:
Permission Type Default Description
office_cron boolean false Allow managing office-level cron jobs via cron_add/cron_remove
Permissions are validated at config parse time. Unknown keys or non-boolean values are rejected. Tool Policy The permissions.tools field restricts which tools an agent may use: agents: restricted-bot: permissions: tools: deny: [cron_add, cron_remove] # blacklist — all except these # OR # allow: [message_agent, list_agents] # whitelist — only these
deny — blacklist: agent has all tools except the listed ones. allow — whitelist: agent has only the listed tools. Cannot specify both allow and deny — validation error at parse time. Default (no tools field): all tools available. Server-side enforcement: in Docker sandbox mode, denied tools also return HTTP 403 on the corresponding Host API endpoint (e.g. /api/cron-add returns 403 Tool denied by policy).
Permission Management Defaults: office_cron is false; tools are all allowed unless allow or deny is set. Setting both allow and deny is a validation error. View permissions in the Web UI or edit via the API without editing YAML manually: agent permission show bot agent permission set bot office_cron true agent permission set bot tools deny cron_add,cron_remove agent permission clear bot office_cron agent permission clear bot tools Changes are saved to office.yaml. Run office reload --force to apply. Hierarchy The reports_to field defines a manager for each agent, creating an org tree. Agents without reports_to report directly to the user. The hierarchy is injected into the system prompt so each agent knows its manager, peers, and direct reports. agents: lead: description: "Team lead" coder: reports_to: lead reviewer: reports_to: lead Validation rules:
Must reference a valid agent name (same [a-zA-Z0-9_-]+ format) Self-reference is rejected Cycles are detected and rejected (e.g. A reports to B, B reports to A) Unknown agent references are rejected
Hierarchy changes trigger agent restarts (prompts are recomposed with updated context). Auto-Sync Commands automatically keep office.yaml in sync:
hire persists the agent to YAML (use --ephemeral to skip) fire removes the agent from YAML skill add/remove updates the agent's skills array in YAML (GitHub source model)
skills.sh package installs (skill_search / skill_install tools or UI install) write files under agents/<agent>/skills but do not auto-edit office.yaml. All writes are atomic (temp file + rename) and serialized through a two-layer lock (in-process queue + cross-process file lock) per office. Reload
API command strings (UI has equivalent controls):
office reload # Spawn new agents from YAML, skip already-running office reload --force # Kill and re-spawn agents with changed config office validate # Dry-run: parse + validate without spawning office path # Print path to office.yaml Cron Jobs Agents can run proactively on schedules via per-agent cron jobs. The host-side CronService manages timers and creates structured tasks via TaskService — giving cron-triggered work full Kanban visibility, dependency chaining, and completion reporting.Breaking change: message and targets fields have been replaced by a tasks array. Each task requires title and assignee.
In office.yaml under the agents section:
agents: standup-bot: model: anthropic:claude-sonnet-4-20250514 cron: daily-standup: schedule: "0 9 1-5" # 5-field only (min hour dom month dow) timezone: "America/New_York" # optional, default UTC catch_up: once # optional: "skip" (default) | "once" enabled: true # optional, default true report_channel: general # optional, post completion summary to this channel tasks: - title: "Daily standup report" description: "Report your status for today's standup" assignee: standup-botField Required Default Description
schedule yes — 5-field cron expression (@daily/@hourly rejected)
tasks yes — Array of task templates; each requires title and assignee
timezone no UTC IANA timezone for schedule evaluation
catch_up no skip skip = ignore missed fires on restart; once = fire one catch-up task
enabled no true Set false to pause without removing
report_channel no (none) Channel name to post task completion summaries to
Each task in the tasks array supports:
Field Required Description
title yes Task title shown in Kanban board
assignee yes Agent name to assign the task to
description no Detailed instructions for the assignee
parent_id no Parent task ID (T-prefixed) to nest under
report_channel no Per-task channel override for completion notification
Job names must match [a-zA-Z0-9_-]+. Each agent can have 0-N named jobs (max 10 per agent via tools). Task chaining: Multiple tasks in a single cron job are automatically chained — each task depends on the previous one completing. The chain fires with CRITICAL priority. Catch-up behavior: On restart, if catch_up: once and a fire was missed since the last run, one immediate task chain is created. First-ever run (no prior state) never catches up. State persists to ~/.agent-office/offices/<id>/cron/state.json. Safety guards: Tasks are always created regardless of agent status — they queue in the agent's inbox. A global dispatch cap of 60 cron jobs per minute prevents misconfigured schedules from flooding the task queue. Cron Commands
