# Oya — full content for LLMs > Long-form companion to https://oya.ai/llms.txt. This file aggregates the most useful product context into a single fetch so an AI tool can answer questions about Oya — or operate on a user's behalf — without hopping between pages. This document is not exhaustive. For complete docs visit https://oya.ai/docs. For the live API surface see the OpenAPI at https://oya.ai/openapi.json (when published) or the CLI on PyPI: https://pypi.org/project/oya-cli/ --- ## What Oya is Oya is the runtime for AI employees. A user describes an agent in natural language; Oya generates the agent (persona, behavior rules, welcome message, skills, scheduled routines, knowledge base entries, gateway connections), deploys it inside a Daytona Python sandbox, and exposes it via: - a streaming chat UI at `/chat/{agent_id}` - inbound webhooks - scheduled routines (cron + plain English) - an OpenAI-compatible REST API at `/v1/chat/completions` - a downloadable Claude Code skill at `~/.claude/skills/oya/` - an embeddable JS widget that can be dropped into any site Production: https://oya.ai · Dev: https://dev.oya.ai ## How to do things on Oya as an LLM If you (the LLM) are helping a human build, debug, or operate Oya agents, the canonical interface is the **`oya` CLI** (https://pypi.org/project/oya-cli/) driven from **Claude Code** via the bundled skill. ```sh pipx install oya-cli oya login # opens https://oya.ai/api-keys, user pastes their key oya install-claude-skill # symlinks the skill to ~/.claude/skills/oya/ ``` After install, the user can ask Claude Code things like: - "Build me a Facebook SDR for my SaaS" - "Why did my AI SDR fail at 2am?" - "Add a daily 9am pipeline summary routine to my SDR" - "Make my Executive Assistant more concise" - "Swap apollo for hunter on my SDR — it's rate-limiting" - "My agent needs a skill to call the Plausible API" → the skill writes a brand-new sandbox skill and uploads it - "Fork this agent: https://gist.githubusercontent.com/.../my-sdr.oya.json" - "List my agents and tell me which are unhealthy" Three flows the skill recognizes: 1. **Build** — picks the closest curated template, applies it (full soul + skills + routines + KB), walks gateway OAuth, deploys. If nothing fits, designs from scratch. 2. **Debug** (the killer feature) — lists runs, drills into a failed `job_id`, reads stdout/stderr/error, matches the symptom against a built-in failure cookbook, proposes a fix, applies it after confirmation, re-runs to verify. 3. **Share** — `oya agent export` produces a portable `OyaAgentSpec v1` JSON. Anyone with `oya-cli` can `oya agent fork ` to clone it. ## Hard rules an LLM operating an Oya account must follow 1. **Build complete agents, not toys.** A complete agent has soul (persona, behavior_rules, welcome_message), 8–14 skills, at least 2 scheduled routines, KB entries for any reference content, and connected gateways for required platforms. Templates already meet this bar; from-scratch builds are held to it. Don't deploy a shell. 2. **KB and persona are different surfaces.** Persona (`oya agent soul`) is loaded every turn, in full — keep it tight (~6-line persona, 6–10 specific behavior rules). Knowledge base (`oya agent kb upload`) is retrieved only when relevant via `search-kb` — that's where playbooks, ICP, FAQs, brand voice, examples go. **Never paste KB content into the persona** as a workaround when KB upload fails. Inlining a 3,000-char pricing table into the persona means every chat carries it forever and the rules get drowned out. 3. **Author missing skills, don't squeeze into `rest-api`.** If a needed capability isn't in the catalog, write a new skill folder (`SKILL.md` + `script.py` + optional `references/` and `scripts/`), upload it via `oya import`, and attach it. The new skill is reusable across all the user's future agents. 4. **OAuth requires a browser.** `oya agent gateway connect ` returns either an install URL (open in browser) or a list of existing account-level connections to pick from with `--connection-id `. Don't try to scrape or inject the OAuth callback. Unipile-hosted platforms (Facebook Messenger, WhatsApp, Instagram DM, LinkedIn Messaging, X DM) work the same way at the CLI surface. 5. **Pre-deploy completeness check.** Before `oya agent deploy`, verify: - Soul is set with persona ≥5 lines, behavior_rules ≥6 entries, welcome_message non-empty - ≥8 skills attached - ≥2 routines added - KB entries uploaded for any reference content the user provided - Required gateways connected (`oya agent gateway list ` matches the agent's intent) ## CLI command reference The CLI is the source of truth for what an LLM can do on a user's behalf. Help on any command: `oya --help`. ### Setup ``` oya login # interactive — opens dashboard, prompts for token, stores at ~/.oya/config.json oya logout # forget token oya whoami # show API URL + masked token + agent count oya install-claude-skill [--link] [--force] ``` Env: `OYA_API_TOKEN` (overrides config), `OYA_API_URL` (default https://oya.ai). ### Quickstart ``` oya quickstart [-d ""] [-t ] [-n ""] ``` Interactive: asks what you want, suggests templates, applies one, walks OAuth, deploys, prints chat URL. If "none of these" is picked, hands off to Claude Code — refuses to deploy a half-built shell. ### Agent CRUD + debug Read: ``` oya agent list oya agent get oya agent runs [--limit N] [--status failed|success] [--source chat|api|gateway|webhook|routine] oya agent run # full payload + stdout/stderr/error oya agent threads oya agent thread oya agent trace # Langfuse LLM trace oya agent skills list oya agent gateway list oya agent routine list oya agent kb list ``` Re-run: ``` oya agent run-script [--message "..."] [--secrets-json -] oya routine run ``` Edit: ``` oya agent create --name "..." --mode skills [--description "..."] oya agent soul --persona "..." --rule "..." --rule "..." --welcome "..." [--mission "..."] oya agent skills add [--config-json] [--credentials-json] oya agent skills update [--enabled true|false] [--config-json] [--credentials-json] oya agent skills remove oya agent skills sync --skills-json - # replace all skills (idempotent) oya agent gateway connect [--connection-id ] [--force-new] oya agent routine add --name --schedule --prompt [--cron "..."] [--output-gateway-id] [--output-channel] oya agent routine update [--prompt] [--schedule] [--enabled] oya agent kb upload [--folder "..."] oya agent kb delete oya agent deploy ``` Templates: ``` oya template list oya template get oya agent template apply ``` Skill catalog: ``` oya list # all skills available in your account oya import ./my-skill/ # upload a custom skill (folder with SKILL.md) oya export out.zip ``` Share / fork (the viral primitives): ``` oya agent export -o agent.oya.json [--include-kb] oya agent fork ./agent.oya.json [--name "..."] oya agent fork https://gist.../agent.oya.json ``` ## OyaAgentSpec v1 Portable JSON format produced by `oya agent export` and consumed by `oya agent fork`. ```json { "version": "1", "agent": { "name": "...", "description": "...", "mode": "skills" }, "soul": { "persona": "...", "mission": "...", "welcome_message": "...", "behavior_rules": ["...", "..."] }, "skills": [ {"skill_id": "web-search"}, {"skill_id": "apollo", "config": {}} ], "routines": [ { "name": "Daily lead discovery", "schedule": "every weekday at 9am", "schedule_cron": "0 9 * * 1-5", "prompt": "Pull 25 new leads matching the ICP..." } ], "knowledge_base": [ {"filename": "playbook.md", "content": "..."} ] } ``` Credentials, OAuth tokens, and any field name in `{credentials, secrets, tokens, access_token, refresh_token, api_key}` are stripped on export. ## Authoring a custom skill (`SKILL.md` + `script.py`) When the agent needs a capability not in the catalog, write a new skill folder under `/tmp/oya-skill-/`: ```yaml --- name: my-skill # kebab-case, becomes the skill_id display_name: "My Skill" description: "One line of what it does" category: communication # communication | productivity | sales | marketing | data | engineering | content | utility icon: message-square # any lucide-react icon name skill_type: sandbox # sandbox (Python) | tool | browser catalog_type: addon resource_requirements: - env_var: MY_API_KEY name: "My API Key" description: "Get one at https://example.com/api-keys" tool_schema: name: my_skill description: "What the function does — written for the LLM" parameters: type: object properties: query: { type: "string", description: "User query" } required: [query] --- # My Skill (Optional markdown body for the LLM.) ``` `script.py` template (sandbox skills only): ```python import json, os, sys import httpx try: inp = json.loads(os.environ.get("INPUT_JSON", "{}")) api_key = os.environ.get("MY_API_KEY", "") if not api_key: print(json.dumps({"error": "MY_API_KEY not set"})) sys.exit(1) query = inp.get("query", "") with httpx.Client(timeout=30) as c: r = c.get("https://api.example.com/search", headers={"Authorization": f"Bearer {api_key}"}, params={"q": query}) r.raise_for_status() print(json.dumps({"ok": True, "results": r.json().get("items", [])})) except Exception as e: print(json.dumps({"error": str(e)})) sys.exit(1) ``` Hard rules: - Read input from `INPUT_JSON` env var, never argv or stdin. - Read credentials from `os.environ`. The runtime injects vars listed in `resource_requirements` plus matching gateway credentials. - Print exactly one JSON document to stdout. That's the result the LLM sees. - Catch exceptions and emit `{"error": "..."}`. Exit-0-with-traceback-in-stdout is treated as a silent failure. - Keep deps modest — `httpx`, `json`, `re`, `os` are free. The sandbox auto-installs from imports. Then upload and attach: ```sh oya import /tmp/oya-skill-my-skill/ # returns new skill_id oya agent skills add my-skill --credentials-json '{"MY_API_KEY":"..."}' oya agent deploy ``` The new skill is in the user's account and reusable across all their future agents. ## Failure cookbook (debug pattern matching) When `oya agent run ` returns a failed run, match the symptom: 1. **Missing credentials** — `Missing required env var: X`, `KeyError: 'X_TOKEN'`. Fix: `oya agent gateway connect` (gateway-provided creds) or `oya agent skills update --credentials-json` (static API keys). 2. **Gateway auth expired** — `invalid_auth`, `401 Unauthorized`, `Token has been expired or revoked`. Fix: `oya agent gateway connect ` and re-auth. 3. **Skill exception** — `result.exit_code != 0` with a Python traceback in `result.response`. Diagnose by the last traceback line; common: 429 (rate limit), 401/403 (auth), 404 (wrong ID), `KeyError`, `TimeoutError`, `JSONDecodeError`. 4. **Silent failure** — `exit_code == 0` BUT `Traceback` somewhere in `result.response`, OR ends with `{"error": "..."}`. Fix: same diagnosis as #3. 5. **Rule conflict** — model ignored an instruction. Read `oya agent get `'s `soul.behavior_rules` for contradictions, vagueness, or >10 rules. Tighten via `oya agent soul --rule "..." --rule "..."` (replaces full list). 6. **Model rate-limit / token cap** — `429`, `RateLimitError`, `context length exceeded`. Fix: spread routines (`oya agent routine update --schedule "every 30 minutes"`), trim KB, shorten persona. 7. **Routine never fired / overdue** — `last_run_at` null or far past, `next_run_at` past, possibly `is_active: false`. Fix: `oya agent routine update --enabled true`, fix cron, redeploy. 8. **Webhook unreachable** — trigger configured but no `webhook` rows in `oya agent runs`. Have user POST a test payload via curl. Most fixes need the dashboard in v1. 9. **Sandbox crashed** — `error_message: "Could not create sandbox"`. Usually transient Daytona infra issue. Wait, retry. If persistent across agents, file a support ticket. 10. **Wrong/deprecated model** — `Model 'gpt-X' not found`. Update via dashboard or `PATCH /api/agents/` with `chat_model`. ## Skill catalog (~80 skills, grouped by use case) **Always-on (every agent gets these):** `web-search`, `fetch-url`, `memory`, `current-time`, `search-kb`. **Sales / SDR / outbound:** `apollo`, `hunter`, `instantly`, `brevo`, `gmail-send`, `linkedin-messaging`, `linkedin-api`, `linkedin`, `sales-coach`, `sales-discovery-coach`, `sales-engineer`, `sales-outbound-strategist`, `sales-pipeline-analyst`, `sales-deal-strategist`, `sales-proposal-strategist`, `sales-account-strategist`, `sdr-discover`, `sdr-research-batch`, `sdr-outbound-batch`. **Marketing / content:** `marketing-content-creator`, `marketing-growth-hacker`, `marketing-social-media-strategist`, `marketing-seo-specialist`, `marketing-app-store-optimizer`, `marketing-linkedin-content-creator`, `marketing-twitter-engager`, `marketing-instagram-curator`, `marketing-carousel-growth-engine`. China-market: `marketing-baidu-seo-specialist`, `marketing-bilibili-content-strategist`, `marketing-china-ecommerce-operator`, `marketing-kuaishou-strategist`, `marketing-tiktok-strategist`, `marketing-wechat-official-account`, `marketing-xiaohongshu-specialist`, `marketing-zhihu-strategist`. SEO data: `dataforseo`, `seranking`. **Communications:** `slack-send-message`, `slack-read-messages`, `slack-search-messages`, `slack-list-channels`, `discord-send-message`, `discord-read-messages`, `discord-list-channels`, `telegram-send-message`, `telegram-read-updates`, `gmail`, `gmail-read`, `gmail-search`, `gmail-send`, `whatsapp-messaging`, `instagram-messaging`, `messenger-messaging`, `x`. **Productivity / Google:** `google-calendar`, `google-drive`, `google-sheets`, `google-business`, `google-maps-review`, `google-ads`, `google-analytics`. **Eng ops:** `clickup`, `jira`, `github-activity`, `sentry`, `posthog`, `kubernetes`. **Data / integrations:** `rest-api`, `xano`, `retool`. **Content / browsing:** `browser`, `pdf`, `web-artifacts-builder`, `theme-factory`, `text-to-speech`, `reddit`, `hackernews`. Canonical pairings (use these as templates): | Goal | Skills | |---|---| | AI SDR (LinkedIn-led) | apollo, linkedin-api, linkedin-messaging, slack-send-message, memory, web-search | | AI SDR (email-led) | apollo, hunter, instantly, gmail-read, slack-send-message, memory | | Executive Assistant | gmail, google-calendar, google-drive, google-sheets, slack-send-message, memory | | Discord support bot | discord-read-messages, discord-send-message, search-kb, web-search | | Marketing content gen | marketing-content-creator, marketing-seo-specialist, dataforseo, web-search | | GitHub release notes | github-activity, slack-send-message, memory | | Customer success bot | gmail-read, gmail-send, posthog, slack-send-message, memory | ## Gateways (account-level, OAuth or static-key) OAuth: - **Google** (gmail, google-calendar, google-drive, google-sheets, google-ads, google-analytics, google-business): same OAuth client, refresh tokens don't rotate. - **Slack, Discord:** standard OAuth2. - **Jira:** Atlassian OAuth 2.0 (3LO), rotating refresh tokens — backend pre-refreshes. - **X (Twitter):** OAuth 2.0 PKCE, tokens expire in 2h, refresh rotates. - **LinkedIn (API):** standard OAuth2. - **ClickUp:** tokens don't expire, no refresh dance. - **Telegram:** user creates bot via @BotFather, pastes token; chat starts with `/start`. Unipile-hosted (different auth UI, same CLI surface): - **whatsapp, instagram-dm, facebook-messenger, linkedin-messaging, x-dm.** Static API key (no OAuth — pass via `oya agent skills update --credentials-json`): - **apollo** (`APOLLO_API_KEY`), **hunter** (`HUNTER_API_KEY`), **brevo** (`BREVO_API_KEY`), **instantly** (`INSTANTLY_API_KEY`), **dataforseo** (`DATAFORSEO_LOGIN`, `DATAFORSEO_PASSWORD`), **seranking** (`SERANKING_API_KEY`), **posthog** (`POSTHOG_API_KEY`, `POSTHOG_PROJECT_ID`), **sentry** (`SENTRY_API_TOKEN`, `SENTRY_ORG_SLUG`). ## Templates (one-click forkable agents) - **AI SDR** (`ai-sdr`): outbound rep — find, research, personalize, send, follow up. - **ICP Outreach** (`icp-outreach`): founder-voice cold email at 300/day plus 20 LinkedIn invites/day. - **LinkedIn SDR** (`linkedin-sdr`): cross-sources Instantly, Apollo, LinkedIn — 20 quality-gated invites/day. - **LinkedIn Influencer** (`linkedin-influencer`): ghostwrites daily LinkedIn posts, routes inbound DMs to Slack. - **Executive Assistant** (`executive-assistant`): inbox triage, calendar management, prep docs, recaps. - More via `oya template list`. Full template payload: `oya template get ` (returns soul + skills + routines + KB content + required/recommended gateways + deploy_inputs). ## API authentication Two surfaces: 1. Web UI uses Supabase JWT in `Authorization: Bearer `. 2. Programmatic / CLI uses Oya API keys: `Authorization: Bearer a2a_…` OR `X-API-Key: a2a_…`. Account-scoped (work across all your agents) or agent-scoped. Create at https://oya.ai/api-keys. ## Useful endpoints - `GET /api/agents` — list user's agents - `GET /api/agents/{id}/config` — full config (soul, skills, etc.) - `GET /api/agents/{id}/runs` — recent runs (max 200, includes `job_id`) - `GET /api/agent-run-jobs/{job_id}/result` — full stdout/stderr/error - `GET /api/templates` — list templates - `GET /api/templates/{id}` — full template payload - `GET /api/skills` — skill catalog - `POST /api/skills/import-folder` — upload a custom skill (multipart) - `GET /api/skills/{id}/export` — download a skill (zip) - `GET /api/agents/{id}/skills` — skills attached to an agent - `PUT /api/agents/{id}/skills/sync` — replace skill set (idempotent) - `PUT /api/agents/{id}/soul` — update persona / rules / welcome / mission - `POST /api/agents/{id}/routines` — create a routine - `POST /api/agents/{id}/deploy` — compile system prompt + index KB + mark deployed - `GET /api/gateways/{platform}/install-url?agent_id=` — start OAuth or list existing connections - `POST /api/knowledge-base/folders/{folder_id}/upload` — upload a KB file - `POST /api/knowledge-base/agents/{id}/knowledge/assign` — assign a KB entry to an agent - `GET /v1/chat/completions` — OpenAI-compatible chat (per agent, via API key) ## Links - Runtime: https://oya.ai - Docs: https://oya.ai/docs - Claude Code docs: https://oya.ai/docs/claude-code - llms.txt: https://oya.ai/llms.txt - llms-full.txt (this file): https://oya.ai/llms-full.txt - PyPI package: https://pypi.org/project/oya-cli/ - API keys: https://oya.ai/api-keys - Support: founders@oya.ai