--- name: agent-builder description: Create and configure a Major agent — a versioned two-file bundle (agent.jsonc + prompt.md) edited on a sandbox — what each field means, how to research connectors and applications before writing the prompt, and the edit/validate/save/publish lifecycle. --- # Building a Major agent An _agent_ in Major is a saved AI configuration users can invoke. It is a **versioned two-file bundle** you author on the agent's own sandbox: ``` agent.jsonc name, description, model, skills, env keys, connectors + applications (with their per-tool permission decisions nested inline) prompt.md the system prompt — the file IS the prompt, no wrapper ``` If you don't have enough information to write a good system prompt or pick connectors, ask the user — it is better to ask than to guess. Finding, creating, and opening agents is on `mcp__plugin_major_major__*` (`list` and `create` with `target_type: "agent"`, `start_sandbox`). File editing goes through the sandbox tools `mcp__plugin_major_major__sandbox_*` (`sandbox_read_file`, `sandbox_edit_file`, `sandbox_write_file`, `sandbox_bash`), each called with `agent: ""` as the target. Sync and publishing are the `major` CLI, run through `sandbox_bash` in `/workspace/agent`: `major pull`, `major push -m ""`, `major validate`, `major publish --yes`. ## The working files, saving, and publishing The working copy lives on the agent's sandbox under the workspace root. Two separate steps take it off the sandbox: - **Save** (`major push`) validates the bundle and writes it as a new immutable version. Nothing the agent runs changes — saving is free. **The sandbox is torn down once it goes idle and comes back seeded from the last saved version, so anything unsaved is lost.** - **Publish** (`major publish --yes`) points the agent at its latest saved version. This makes the agent live. An agent with no published version can't be run deployed at all — starting a session against it fails with "no published version yet". So a brand-new agent needs one `major publish --yes` before anyone can use it. Always use an `agentId` returned by `list` or `create` (`target_type: "agent"`) — never invent one. If this chat is pinned to an agent, the "Working with this agent" section of your system prompt carries the bound-chat rules (omit ids to target it). ## Save discipline - **Never `major pull` routinely** — it overwrites the sandbox files with the last saved version and destroys any unsaved edits, the user's included. Pull only to recover corrupted files or on the user's explicit ask to discard. - **Always `major push` before you finish a turn in which you edited files.** Unsaved work dies with the sandbox. Saving needs no permission and changes nothing about what the agent runs. - **Publish only when the user asks for it.** That is the moment the agent's behaviour changes for everyone. ## Lifecycle - **Edit existing**: `list({target_type: "agent"})` to find it, then `start_sandbox({agent: ""})` — it mounts (or joins) the agent's sandbox. Edit the two files with the sandbox tools, saving as you finish each round. - **New**: `create({target_type: "agent", name, description})` — creates the agent (server-minted `agentId`), mounts its sandbox seeded with a scaffold bundle, and returns where the files live. - **Check a draft**: `major validate` — parses `agent.jsonc` against the schema without saving. Saving validates too (and additionally checks that every referenced skill/connector/app exists in the org); on failure nothing is saved and the error list comes back. - **Save**: `major push -m ""` — every save writes a new immutable version. - **Publish**: `major publish --yes` — makes the latest saved version live. Only on the user's explicit go-ahead. ## `agent.jsonc` The definition shape — fields, the allowed model ids, permission decisions — is the JSON Schema the Major API serves at `GET https://api.prod.major.build/public/agent.schema.json`, the single source of truth. YOU MUST CURL THIS SCHEMA BEFORE WRITING `agent.jsonc`; its `x-validatorRules` carry the rules beyond shape (membership grants access, ids must exist in the org, bundle is exactly the two files). `major validate` and every `major push` enforce all of it, with errors naming the offending path. ## Tool permissions **Sensible defaults are already applied — usually don't touch this.** Read-only tools and `GET` endpoints default to `always_allow`; writes and every non-`GET` method default to `ask`. Only list a tool or endpoint explicitly when the user wants to deviate (e.g. "never let it delete anything"). To see the current picture: `major agent permissions --resource ` / `major agent permissions --app ` (run through `sandbox_bash` in `/workspace/agent`) list every tool/endpoint with its decision **as of the published version**. To change one, edit that connector's `tools` (or that app's `endpoints`) array in `agent.jsonc`, then push and publish — there is no live permission-editing tool. ## Env variables The bundle declares which env **keys** a version wants. A non-secret value can sit right next to its key in `agent.jsonc`. A key set to `null` has no value in the bundle, and the user supplies one. **You never set a value, and you never see one.** Add the key to `env` with `null`, push, and tell the user to fill it in — the env section of the agent panel, on the right, lists every declared key with a value box. The value is stored encrypted per `(agent, key)` and shared across versions, so it survives every save, publish and rollback. There is no tool that sets an agent's env value. On Slack there is no panel. Tell the user to open the agent in the web app to fill in a value. ## Picking connectors and applications - Use `mcp__plugin_major_major__execute_resource_tool` with `toolName: "mcp__resources__list_resources"` to list the org's connectors; `mcp__plugin_major_major__list` with `target_type: "app"` lists attachable apps. **Call it without `include_read_only`** — an agent can only be granted apps the user can edit. - If no existing connector matches, call `mcp__plugin_major_major__request_resource_setup` to prompt the user to create one inline. `connectorId` is required — pass one you already know (e.g. `"postgresql"`, `"snowflake"`) or use `mcp__plugin_major_major__execute_resource_tool` with `toolName: "mcp__resources__search_connector_types"` to discover the connectors you can set up; ask if unsure. The tool blocks until the user finishes or declines; on success add the returned `resourceId` to `connectors` in `agent.jsonc`. - Slack is provisioned automatically when the user installs the Major Slack integration (Settings → Integrations) and is intentionally not a creatable connector — if it's missing from `list_resources`, tell them to install the integration. - If an existing connector needs more configuration to be usable (e.g. selecting a Google Sheets spreadsheet), call `mcp__plugin_major_major__request_resource_update` with the `resourceId` and what's missing. - Don't add connectors or applications speculatively — every one expands the agent's permissions. Keep the set minimal. ## Research before writing the prompt A good system prompt names the actual tables, endpoints, and fields the agent will use — not "query the database". Probe what you attached before writing: - **Connectors:** pass the matching canonical `mcp__resources__*` tool name to `mcp__plugin_major_major__execute_resource_tool` — `information_schema` + a few sample rows for SQL databases, object/property lists for CRMs, bucket/key listings for S3, an introspection or health call for APIs. Canonical resource tools are execution targets, not directly callable tools. Stop once you can write a confident prompt — you're not building a data dictionary. - **Applications:** call `get_app_skill({applicationId})` first (it returns the endpoints and request/response shapes — usually enough). Probe live endpoints with `do_get_request` only if something is still unclear, and never issue writes via `do_requests` just to learn a shape — ask the user first. Then cite what you found in `prompt.md`: "query `analytics.daily_sessions` filtered by `user_id`", not "ask the database about sessions". A good prompt is 5–20 lines — if the user gives you a one-liner, draft a proper prompt yourself, after the research, not before. ## Attaching skills Skills are reusable instruction bundles authored in the Skill Library; attached skills auto-load when the agent's sessions start. `list_attachable_skills` returns `{id, slug, description}`; add the ids you want to the `skills` array in `agent.jsonc`. Attach only skills whose `description` clearly fits the agent's job — a skill the model never uses is noise. If no fitting skill exists and the user has described one, use the `skill-builder` skill to build it. ## Running on a schedule An agent has **no schedule of its own** — running an agent on a cadence is a property of a _workflow_ whose trigger fires the agent. If the user wants this agent to run on a schedule, load the `workflow-builder` skill and build a workflow there. ## Connecting the agent to Slack An agent can get its own Slack bot so people @mention it in their workspace. Manage it with the `major` CLI, run through `sandbox_bash` in the agent sandbox's `/workspace/agent` (the folder names the agent, so no `--id` is needed there): - `major agent slack connect` provisions a dedicated Slack app and prints the install URL. Give it to the user to open. - `major agent slack pause` / `major agent slack resume` silence and re-enable it. - `major agent slack delete --yes` is permanent — reconnecting later creates a brand-new bot identity that won't reattach to existing threads, so only on the user's explicit ask. ## Running the agent Runs use the agent's **published** version, so publish first. Start a run with the Major MCP `run_agent({agentId, prompt})` tool; the user approves it, and it returns a `runId`. (`major agent run` is refused in a sandbox, because only the MCP tool asks the user.) Then, in `/workspace/agent`: - `major agent run list --mine` lists your runs, newest first (`--live`, `--source `, `--limit`, `--offset` narrow it). - `major agent run content ` reads the run's messages. - `major agent run send -m ` sends a follow-up (a finished run resumes). - `major agent run stop ` stops it.