Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion plugins/major-build/.claude-plugin/plugin.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,6 @@
},
"repository": "https://github.com/major-technology/cli",
"license": "MIT",
"skills": "./skills/"
"skills": "./skills/",
"mcpServers": "./.mcp.json"
}
10 changes: 10 additions & 0 deletions plugins/major-build/.mcp.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"major": {
"type": "http",
"url": "${MAJOR_MCP_URL:-https://mcp.major.build/mcp}",
"headers": {
"x-major-jwt": "${MAJOR_RESOURCES_API_TOKEN:-}"
},
"alwaysLoad": true
}
}
26 changes: 13 additions & 13 deletions plugins/major-build/skills/agent-builder/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,36 +15,36 @@ 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.

Orchestrator tools are `mcp__orchestrator-platform__*` (`list_editable_agents`, `mount`, `create_agent`, `get_agent`, `publish`). File editing and sync go through the sandbox tools `mcp__sandbox__*` (`read_file`, `edit_file`, `write_file`, `pull`, `push`, `validate`), each called with `agent: "<agentId>"` as the target. `publish` takes the same `agent` argument.
Finding, creating, and opening agents is on `mcp__plugin_major-build_major__*` (`list_agents`, `create_agent`, `start_sandbox`); orchestrator tools are `mcp__orchestrator-platform__*` (`get_agent`, `publish`). File editing and sync go through the sandbox tools `mcp__plugin_major-build_major__sandbox_*` (`sandbox_read_file`, `sandbox_edit_file`, `sandbox_write_file`, `sandbox_pull`, `sandbox_push`, `sandbox_validate`), each called with `agent: "<agentId>"` as the target. `publish` takes the same `agent` argument.

## 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** (`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.**
- **Save** (`sandbox_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** (`publish`) 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 `publish` before anyone can use it.

Always use an `agentId` returned by `list_editable_agents` or `create_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).
Always use an `agentId` returned by `list_agents` or `create_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 `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 `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.
- **Never `sandbox_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 `sandbox_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_editable_agents` to find it, then `mount({agent: "<agentId>"})` — it mounts (or joins) the agent's sandbox. Edit the two files with the sandbox tools, saving as you finish each round.
- **Edit existing**: `list_agents` to find it, then `start_sandbox({agent: "<agentId>"})` — it mounts (or joins) the agent's sandbox. Edit the two files with the sandbox tools, saving as you finish each round.
- **New**: `create_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**: `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**: `push({notes})` — every save writes a new immutable version.
- **Publish**: `publish({agent})` — makes the latest saved version live. Name the target the same way the sandbox tools do: pass the `agentId` you passed to `push`. Only on the user's explicit go-ahead. Add `versionId` to roll back to an earlier version.
- **Check a draft**: `sandbox_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**: `sandbox_push({notes})` — every save writes a new immutable version.
- **Publish**: `publish({agent})` — makes the latest saved version live. Name the target the same way the sandbox tools do: pass the `agentId` you passed to `sandbox_push`. Only on the user's explicit go-ahead. Add `versionId` to roll back to an earlier version.

## `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). `validate` and every `push` enforce all of it, with errors naming the offending path.
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). `sandbox_validate` and every `sandbox_push` enforce all of it, with errors naming the offending path.

## Tool permissions

Expand All @@ -66,8 +66,8 @@ On Slack there is no panel. Tell the user to open the agent in the web app to fi

## Picking connectors and applications

- Use `mcp__resources__execute_resource_tool` with `toolName: "mcp__resources__list_resources"` to list the org's connectors; `mcp__orchestrator-platform__list_edit_apps` lists attachable apps. **Use `list_edit_apps`, not `list_use_apps`** — an agent can only be granted apps the user can edit.
- If no existing connector matches, call `mcp__interactions__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__resources__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`.
- Use `mcp__plugin_major-build_major__execute_resource_tool` with `toolName: "mcp__resources__list_resources"` to list the org's connectors; `mcp__plugin_major-build_major__list_apps` lists attachable apps. **Use `list_apps`, not `list_use_apps`** — an agent can only be granted apps the user can edit.
- If no existing connector matches, call `mcp__interactions__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-build_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__interactions__request_resource_update` with the `resourceId` and what's missing.
- After adding skills, call `list_suggested_connectors` — it returns connectors the attached skills' scripts actually use that the agent can't access yet. Propose them to the user and add accepted ones to `connectors`; a skill whose connector is missing will fail at runtime. Entries with `canAdd=false` need access the current user doesn't have — tell them to ask an admin.
Expand All @@ -77,7 +77,7 @@ On Slack there is no panel. Tell the user to open the agent in the web app to fi

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__resources__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.
- **Connectors:** pass the matching canonical `mcp__resources__*` tool name to `mcp__plugin_major-build_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.
Expand Down
18 changes: 9 additions & 9 deletions plugins/major-build/skills/app-builder/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,16 +9,16 @@ An _app_ on Major is a full-stack Next.js app: frontend and backend API routes,

Treat apps as **compute**. Whenever you need to run code, use an app. Apps also visualize results for the user. Offload deterministic behavior into the app; agents and workflows call it.

The main way to work on an app is to mount its sandbox onto this chat and edit it yourself. Orchestrator tools are `mcp__orchestrator-platform__*` (`list_edit_apps`, `create_app`, `mount`, `list_sandboxes`, `unmount_app_sandbox`). File and shell work go through the `mcp__sandbox__*` tools — the "Working with sandboxes" section of your system prompt covers the tools, argument conventions, provisioning, shared-sandbox etiquette, and local-file uploads; an app's target argument is `slug`. Run `major` CLI commands through `mcp__sandbox__bash` inside the mounted app workspace; they infer the app from the working directory, so do not pass an app ID or run them in the agent's local filesystem. Deployment and app-to-agent wiring still use major-app MCP tools.
The main way to work on an app is to mount its sandbox onto this chat and edit it yourself. Finding, creating, opening, and closing apps is on `mcp__plugin_major-build_major__*` (`list_apps`, `create_app`, `list_sandboxes` for what is mounted, `start_sandbox`, `stop_sandbox`). File and shell work go through the `mcp__plugin_major-build_major__sandbox_*` tools — the "Working with sandboxes" section of your system prompt covers the tools, argument conventions, provisioning, shared-sandbox etiquette, and local-file uploads; an app's target argument is `slug`. Run `major` CLI commands through `mcp__plugin_major-build_major__sandbox_bash` inside the mounted app workspace; they infer the app from the working directory, so do not pass an app ID or run them in the agent's local filesystem. Deployment and app-to-agent wiring still use major-app MCP tools.

You are in general chat — **nothing is bound to this thread**, and a sandbox is not always mounted. Always use an `applicationId` returned by `list_edit_apps` or `create_app` — never invent one. If the app you need is not in `list_sandboxes`, mount it (`mount({app: "<applicationId>"})`) or create it (`create_app`) before using `mcp__sandbox__*` tools.
You are in general chat — **nothing is bound to this thread**, and a sandbox is not always mounted. Always use an `applicationId` or `slug` returned by `list_apps` or `create_app` — never invent one. If the app you need is not in `list_sandboxes`, start it (`start_sandbox({slug: "<slug>"})`, or `app: "<applicationId>"`) or create it (`create_app`) before using `mcp__plugin_major-build_major__sandbox_*` tools.

If this chat is already pinned to an app (the "Working with this app" section of your system prompt), its sandbox is auto-mounted — skip create/mount and edit that app through the sandbox tools with its slug.

## Lifecycle

- **Edit existing**: `list_edit_apps` to find it, then `mount({app: "<applicationId>"})`. This wakes the app's sandbox, attaches it to this chat, and starts a live preview. A `locked` result means another user holds the app — tell the user who; do not retry in a loop.
- **New**: `create_app({name, description})` with a short name and a one-sentence description. It returns the new `applicationId` and automatically mounts the sandbox — you do **not** need to call `mount`. For a brand-new app's first iteration, load the `new-project` skill and follow it before writing code.
- **Edit existing**: `list_apps` to find it, then `start_sandbox({slug: "<slug>"})`. This wakes the app's sandbox, attaches it to this chat, and starts a live preview. A `locked` result means another user holds the app — tell the user who; do not retry in a loop.
- **New**: `create_app({name, description})` with a short name and a one-sentence description. It returns the new `applicationId` and automatically mounts the sandbox — you do **not** need to call `start_sandbox`. For a brand-new app's first iteration, load the `new-project` skill and follow it before writing code.
- **Save**: commit and push on `main` using the sandbox shell tool. Stage only the files you changed (`git add <paths>`) — never `git add -A` or `git add .`: other chat sessions may be editing the same workspace. Never run `git stash` (or `git stash push` / `git stash pop` / `git stash apply`). Never create feature branches.
- **Deploy**: a separate, explicit step — do **not** call `deploy_app` unless the user asked to deploy/publish/ship in this conversation. Finishing an edit means committing and pushing on `main`, then telling the user the change is ready to deploy. When they do ask, batch all finished changes into a single deploy. A deploy builds for ~2 minutes — tell the user it is building and end your turn; never poll `major app info` in a loop.

Expand All @@ -30,10 +30,10 @@ The preview dev server is ALREADY running in the sandbox and hot-reloads on save

- NEVER run `next build`, `pnpm build`, `npm run build`, or `yarn build`. Only run a build if you are specifically debugging a build issue.
- NEVER delete or remove the `.next` directory — it crashes the preview server and the entire session.
- To check for errors, run lint (through `mcp__sandbox__bash`) instead of building. After you finish editing, always run a lint check and fix what it reports — lint failures will fail a deploy. Lint ONCE per finished change, not after every file edit.
- To check for errors, run lint (through `mcp__plugin_major-build_major__sandbox_bash`) instead of building. After you finish editing, always run a lint check and fix what it reports — lint failures will fail a deploy. Lint ONCE per finished change, not after every file edit.
- When using parallel subagents, each subagent should ONLY write code and run lint. Do NOT have subagents run build commands.

The preview/sandbox runtime has these environment variables available — use `mcp__sandbox__bash` with curl to hit the APIs you write:
The preview/sandbox runtime has these environment variables available — use `mcp__plugin_major-build_major__sandbox_bash` with curl to hit the APIs you write:

- `MAJOR_API_BASE_URL` — the base url of the Major API
- `MAJOR_JWT_TOKEN` — the JWT token for the Major API
Expand All @@ -43,7 +43,7 @@ The preview/sandbox runtime has these environment variables available — use `m

Every tool result you pull into this chat is re-read on each later step, so keep results small:

- Don't re-read files you just read or wrote — the content is already in your context. For large files, page with `mcp__sandbox__read_file`'s offset/limit instead of re-reading the whole file.
- Don't re-read files you just read or wrote — the content is already in your context. For large files, page with `mcp__plugin_major-build_major__sandbox_read_file`'s offset/limit instead of re-reading the whole file.
- Push bulk lookups to subagents and have them return conclusions only: database verification queries (postgresql_psql), broad code exploration, and log digging. Don't run row-dump queries in the main chat.
- Do not verify the UI unless explicitly asked. Playwright verification is costly and should be used sparingly.
- When dispatching a subagent (or running a workflow of subagents), explicitly select its model instead of leaving it unset. Prefer a smaller/cheaper model (e.g. haiku) for routine work — bulk lookups, log digging, simple code exploration, mechanical edits — and reserve a larger model for tasks that genuinely need deeper reasoning (architecture decisions, tricky debugging, ambiguous requirements).
Expand All @@ -69,7 +69,7 @@ Run `major app theme get` in the app workspace before frontend work. It returns
Two playbooks — use the relevant one before you start:

- Load the `debug-issue` skill whenever you're investigating a failure, regression, or broken/blank/errored behavior in the app (covers the preview, app errors, logs, and browser inspection).
- Read [references/using-agents.md](references/using-agents.md) (in this skill's directory) when wiring the app's runtime code to trigger Major agents (run / sendMessage / stop / approvals; `add-agent-client` generates the typed client, same pattern as resource clients).
- Read [references/using-agents.md](references/using-agents.md) (in this skill's directory) when wiring the app's runtime code to trigger Major agents (run / sendMessage / stop / approvals; `sandbox_add-agent-client` generates the typed client, same pattern as resource clients).

## Recurring work

Expand All @@ -81,7 +81,7 @@ App code can call LLMs through Major's AI proxy — no API key needed, spend is

## Inspecting

Run these commands in the mounted app workspace through `mcp__sandbox__bash`:
Run these commands in the mounted app workspace through `mcp__plugin_major-build_major__sandbox_bash`:

- `major app info --json` — deployment status, the deployed URL, and visibility
- `major app logs --preview` — preview/dev-server output
Expand Down
Loading
Loading