
Multica Creating Agents
- 17 installs
- 44k repo stars
- Updated August 5, 2026
- multica-ai/multica
Helps with ai & agent building tasks during AI-assisted development.
About
multica-creating-agents is a Claude Code skill for ai & agent building. It helps solo builders move faster with AI-assisted coding.
- multica-creating-agents
- AI & Agent Building
- AI-coding skill
Multica Creating Agents by the numbers
- 17 all-time installs (skills.sh)
- +7 installs in the week ending Aug 4, 2026 (Skillselion tracking)
- Ranked #10,861 of 16,546 AI & Agent Building skills by installs in the Skillselion catalog
- Data as of Aug 5, 2026 (Skillselion catalog sync)
npx skills add https://github.com/multica-ai/multica --skill multica-creating-agentsAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 17 |
|---|---|
| repo stars | ★ 44k |
| Last updated | August 5, 2026 |
| Repository | multica-ai/multica ↗ |
What it does
Helps with ai & agent building tasks during AI-assisted development.
Files
Creating Multica agents
This is the contract for Multica's agent-creation path: what the create entry points accept, what the server validates and rejects, how each field is persisted, and which fields the daemon actually reads at claim time. It is not a parameter manual — it states source-traced facts, and every claim is backed by file:line in references/creating-agents-source-map.md.
Quick start (read-only inspection)
These commands read state and have no side effects:
multica agent get <agent-id> --output json # full persisted agent record
multica agent skills list <agent-id> --output json # current skill bindings
multica agent env get <agent-id> --output json # plaintext env (owner/admin only, agents denied)agent get returns the persisted agent including runtime_id, model, thinking_level, custom_args, has_custom_env, custom_env_key_count, and skills. It never returns plaintext custom_env.
Core model
An agent is a workspace-scoped row (table agent). Creation is a single POST /api/agents (multica agent create). At task claim time the daemon re-reads the agent row and assembles the runtime payload — so the persisted fields, not the create-time output, are what the agent runs on.
Two distinct text fields, often confused:
descriptionis a catalog summary. It is stored and shown in listings; the
daemon does NOT inject it into the agent's runtime prompt. Treat it as human-facing metadata only. Capped at 255 Unicode code points.
instructionsis the runtime behavior contract. The daemon reads it at
claim time and ships it to the provider as the agent's durable instructions. Persona, responsibilities, boundaries, output and escalation rules go here, not in description.
CLI / API entry points
Minimum create call (--name and --runtime-id are both required):
multica agent create --name <name> --runtime-id <runtime-id> \
--description "<short catalog summary>" \
--instructions "<runtime behavior contract>" \
--output jsonrunAgentCreate builds a JSON body and posts it to /api/agents. It only adds a key when its flag was provided — description/instructions on a non-empty value, the rest (runtime-config, custom-args, model, thinking-level, visibility, …) on the flag being Changed — so omitted flags fall through to server defaults rather than sending empty strings.
The HTTP body (CreateAgentRequest) accepts: name, description, instructions, runtime_id, runtime_config, custom_env, custom_args, model, thinking_level, visibility, max_concurrent_tasks, mcp_config.
Field contracts
| Field | Persisted as | Validated? | Consumed by |
|---|---|---|---|
name | agent.name | required, 400 if empty | listings, runtime payload |
description | agent.description | 400 if > 255 code points | catalog/listing only — NOT the runtime prompt |
instructions | agent.instructions | none | daemon → provider at claim time |
runtime_id | agent.runtime_id | required (400) + must resolve to a runtime in this workspace | selects runtime/provider |
model | agent.model (nullable) | none beyond runtime support | daemon reads; empty = runtime default |
thinking_level | agent.thinking_level (nullable) | provider-level enum; unknown literal → 400 | daemon; empty = runtime default |
custom_args | agent.custom_args (JSON array) | JSON shape checked CLI-side; server stores as-is | daemon (extra CLI switches); defaults to [] |
runtime_config | agent.runtime_config (JSON) | JSON shape checked CLI-side; server stores as-is | runtime-specific config; defaults to {} |
custom_env | agent.custom_env (JSON object) | — | daemon (process env); see Env & secrets |
mcp_config | agent.mcp_config (raw JSON) | CLI checks it is a JSON object or null; server stores as-is. At create, literal null is dropped (no-op); at update, null clears the column | daemon → provider (MCP servers) — runtime-consumed; redacted on read |
visibility | agent.visibility | — | access control; defaults to private; gates who can read/route a private agent (e.g. a private squad leader) — NOT the runtime prompt |
max_concurrent_tasks | agent.max_concurrent_tasks | — | scheduler task cap; defaults to 6 |
Defaults when omitted: runtime_config → {}, custom_env → {}, custom_args → [], visibility → private, max_concurrent_tasks → 6 (all materialized server-side before the insert). custom_args/runtime_config are typed []string/any and marshaled as-is — the JSON-shape rejection happens in the CLI, not the create handler.
thinking_level is validated only at the provider level: an unrecognized literal returns 400, but a value that is valid for the provider yet unsupported for the chosen model is NOT rejected here — that gap surfaces as a daemon-side task error at execution time.
Set it from the CLI with --thinking-level on agent create and agent update, mirroring --model: the flag is a thin pass-through to the top-level thinking_level field, and on update an empty string (--thinking-level "") clears it back to the runtime default. The CLI deliberately does not enumerate the valid levels — they are runtime/model-specific (Claude low|medium|high|xhigh|max, Codex none|minimal|low|medium|high|xhigh, and others), so it forwards whatever you pass and lets the server's provider catalog accept or reject it. A runtime whose provider has no thinking concept rejects any non-empty value with a 400.
model vs custom_args
model is a first-class persisted column the daemon reads directly. custom_args are raw provider CLI args. The CLI help notes that some providers (codex app-server, openclaw) reject --model inside custom_args — but that is documented CLI guidance, not a server-enforced invariant; nothing in the create handler inspects custom_args for a model flag.
Env & secrets
custom_env is secret material. The CLI offers three input channels; two keep secrets out of shell history and the process list:
multica agent create --name <name> --runtime-id <runtime-id> --custom-env-stdin --output json
multica agent create --name <name> --runtime-id <runtime-id> --custom-env-file <0600-json> --output json--custom-env-stdin reads the JSON object from stdin; --custom-env-file reads it from a file (suggested mode 0600). The third channel, --custom-env <json>, puts the value on the command line where shell history and ps can see it — avoid it for real secrets.
Read-side facts (these are the wrong assumptions to avoid):
- Agent resources never expose plaintext
custom_env. `agent
list/get/create/update and WS events return only has_custom_env (bool) and custom_env_key_count` (int).
- Reading plaintext values requires the dedicated
GET /api/agents/{id}/env
endpoint (multica agent env get). It is gated to workspace owner/admin members, and agent actors are denied regardless of the backing member's role — a running agent cannot read another agent's secrets.
- Writing values after creation does NOT go through
agent update. The generic
update handler rejects any custom_env field with a 400 ("use PUT /api/agents/{id}/env"). Plaintext env writes are handled by PUT /api/agents/{id}/env (multica agent env set), which is owner/admin-only and writes an audit row.
mcp_config
mcp_config is the agent's MCP server configuration (a JSON object such as {"mcpServers": {…}}). It is also secret material — MCP entries routinely embed API tokens — and offers the same three input channels as custom_env, on BOTH agent create and agent update:
multica agent create --name <name> --runtime-id <runtime-id> --mcp-config-file <0600-json> --output json
multica agent update <agent-id> --mcp-config-stdin --output json
multica agent update <agent-id> --mcp-config 'null' # clears the config--mcp-config-stdin / --mcp-config-file keep the value out of shell history and ps; the inline --mcp-config <json> does not. The CLI requires a JSON object or the literal null; a top-level array or primitive is rejected client-side, and empty stdin/file input errors rather than silently clearing.
Two ways mcp_config differs from custom_env:
- It IS settable through `agent update`. Unlike
custom_env,mcp_config
has no dedicated audited endpoint — the generic PUT /api/agents/{id} accepts it. Tri-state per the raw request body: field omitted → no change; null → clear; object → replace.
- It is serialized on read, but redacted.
agent get/listreturn
mcp_config only to callers allowed to view agent secrets; otherwise the field is null and mcp_config_redacted is true. Agent actors never see it, and a workspace may force redaction for everyone.
Skill binding
Creating an agent does NOT bind any workspace skill — binding is a separate call after the agent exists. Two distinct verbs:
addis additive — it merges the given ids with existing bindings
(POST /api/agents/{id}/skills/add).
setis replace-all — it overwrites the entire binding list with exactly
the given ids (PUT /api/agents/{id}/skills); --skill-ids '' clears all.
multica agent skills add <agent-id> --skill-ids <skill-id> --output json
multica agent skills list <agent-id> --output jsonAt claim time the daemon assembles the agent's skills as workspace-bound skills FIRST, then appends the platform built-in skills. LoadAgentSkills loads each bound skill's content plus its supporting files; built-in skills are embedded at compile time and loaded from SKILL.md + sibling files. Both reach the provider as skill content — which is why capability belongs in a bound skill, not pasted into instructions.
Side effects needing approval
Read-only (safe): agent get, agent skills list, agent env get.
State-changing (require an explicit instruction — do not run speculatively):
multica agent create— inserts a new agent row.multica agent skills add/set— mutate bindings (setis destructive:
it drops bindings not in the new list).
multica agent env set— overwrites the fullcustom_envmap and writes an
audit row.
Common wrong assumptions
- "
descriptionis the prompt." It is not — onlyinstructionsreaches the
runtime. A rich description with empty instructions yields a named shell with no operating contract.
- "Create binds the agent's skills." It does not; bind explicitly afterward.
- "
agent updatecan rotate env." It cannot — it 400s oncustom_env; use the
env endpoint.
- "
mcp_configbehaves likecustom_envon update." It does not —mcp_config
IS settable via agent update (--mcp-config), with --mcp-config null to clear; only custom_env is gated behind the dedicated env endpoint.
- "
agent getshows env values." It shows onlyhas_custom_envand
custom_env_key_count.
- "An invalid
thinking_level/modelcombo is caught at create." Only an
unknown provider-level literal is — model-specific gaps fail at run time.
- "
setandaddare interchangeable for skills."setreplaces all
bindings; using it when you meant add silently removes capabilities.
References
references/creating-agents-source-map.md maps every contract above to its file:line on the current tree, the runtime effect, and a safe read-only verification command.
Creating agents — source map
Evidence layer for SKILL.md. Every contract maps to file:line on the current tree (branch feat/builtin-skills, latest main merged), the runtime effect, and a safe read-only check. Line numbers were re-derived against this tree — re-derive again if the files move, the surrounding context (not the number) is the anchor.
Verification
# Conformance eval for this skill (and the shared template invariants):
go test ./internal/service -run TestCreatingAgentsSkillCoversAgentCreationContracts
go test ./internal/service -run TestBuiltinSkillsConformToTemplateCLI entry points — server/cmd/multica/cmd_agent.go
| Contract | Line | Behavior | Safe check |
|---|---|---|---|
Create flags: name, description, instructions, runtime-id | 159–162 | Registered create flags; name/runtime-id enforced in runAgentCreate | multica agent create --help |
runtime-config, model, thinking-level, custom-args flags | 163–166 | model help: "Prefer this over passing --model in --custom-args"; thinking-level is a thin pass-through (server validates the provider enum, empty = runtime default); custom-args help names codex/openclaw rejecting --model (CLI help only, not server-enforced) | multica agent create --help |
Secret-safe env input: custom-env, custom-env-stdin, custom-env-file | 167–169 | --custom-env warns about shell history / ps; stdin and file modes keep secrets off the command line; mutually exclusive | multica agent create --help |
Secret-safe MCP input: mcp-config, mcp-config-stdin, mcp-config-file (create) | 170–172 | Same three-channel pattern as custom-env; --mcp-config warns about shell history / ps; value must be a JSON object or null | multica agent create --help |
MCP flags on agent update | 194–196 | Same three channels on update; --mcp-config null clears. Unlike custom_env, mcp_config IS settable via update | multica agent update --help |
thinking-level flag on agent update | 184 | New reasoning/effort level; thin pass-through; --thinking-level "" clears to runtime default (mirrors --model) | multica agent update --help |
runAgentCreate builds body + POST /api/agents | 419 | Only sets a body key when the flag Changed; posts to /api/agents (line 495) | read 419–496 |
| Body assembly: description/instructions/runtime-config/custom-args/custom-env/mcp-config/model/thinking-level | 438–488 | resolveCustomEnv (460) and resolveMcpConfig (465) gate their secret channels; model (470) and thinking_level (478) are Changed-gated pass-throughs; omitted flags are not sent | read 438–488 |
runAgentUpdate sends thinking_level / mcp_config | 508 | thinking_level added when --thinking-level is Changed (556); resolveMcpConfig adds mcp_config (570); PUT /api/agents/{id} at 584; custom_env is intentionally not a flag here | read 508–585 |
parseMcpConfig / resolveMcpConfig helpers | 1086, 1114 | Validator (object-or-null, content-free errors) + three-channel resolver, mirroring parseCustomEnv/resolveCustomEnv | read 1086–1170 |
agent skills set = replace-all | 792 | PUT /api/agents/{id}/skills (810); --skill-ids '' clears all (798–799) | multica agent skills set --help |
agent skills add = additive | 817 | POST /api/agents/{id}/skills/add (838); requires ≥1 id (823–828) | multica agent skills add --help |
agent skills list | 760 | reads bindings, no side effect | multica agent skills list --help |
agent env get | 894 | GET /api/agents/{id}/env | multica agent env get --help |
agent env set | 929 | PUT /api/agents/{id}/env with full custom_env map (935, 949) | multica agent env set --help |
Note: the CLI no longer exposes --from-template. The agent-template backend still exists (registry server/internal/agenttmpl/, handler agent_template.go, routes GET /api/agent-templates and POST /api/agents/from-template, plus the packages/core client/query wrappers) but is currently orphaned plumbing with no live caller: the removed CLI flag was its only non-test consumer, and onboarding does NOT use it — packages/views/onboarding/steps/step-agent.tsx builds four hardcoded local presets (i18n-resolved) and creates via plain POST /api/agents (createAgent), never POST /api/agents/from-template. Do not treat the template API as a supported agent-creation path. This skill teaches manual agent create only.
Create handler — server/internal/handler/agent.go
| Contract | Line | Behavior |
|---|---|---|
maxAgentDescriptionLength = 255 | 31 | Cap is 255 Unicode code points (comment: counted via utf8.RuneCountInString, matches Postgres char_length) |
AgentResponse omits plaintext custom_env | 33–53 | Exposes only has_custom_env (52) and custom_env_key_count (53); comment cites MUL-2600 |
CreateAgentRequest fields | 565–585 | description, instructions, runtime_config, custom_env, custom_args, model, thinking_level (plus name/avatar/visibility/mcp_config/max_concurrent_tasks) |
name required | 623–625 | 400 "name is required" |
description ≤ 255 code points | 627–629 | utf8.RuneCountInString(req.Description) > maxAgentDescriptionLength → 400 |
runtime_id required | 631–633 | if req.RuntimeID == "" → 400 "runtime_id is required" |
runtime_id must resolve in workspace | 642–658 | parsed + GetAgentRuntimeForWorkspace; unknown → 400 "invalid runtime_id" |
thinking_level provider-level validation | 673–676 | !agent.IsKnownThinkingValue(runtime.Provider, req.ThinkingLevel) → 400; per-model gaps deferred to daemon (comment 669–672, MUL-2339) |
Defaults: {} config/env, [] args | 688–701 | RuntimeConfig→{}, CustomEnv→{}, CustomArgs→[] when nil, before insert |
visibility default | 635–636 | if req.Visibility == "" { req.Visibility = "private" } — access-control field, not the runtime prompt |
max_concurrent_tasks default | 638–639 | if req.MaxConcurrentTasks == 0 { req.MaxConcurrentTasks = 6 } — scheduler cap |
mcp_config null-skip on create | 704–705 | raw JSON copied through unless the body value is the literal null |
mcp_config redacted on read | 54, 848–851 | redactMcpConfig sets McpConfigRedacted=true; a private agent read by a member also redacts (494, 509) |
CreateAgent insert params | 708–722 | persists runtime_config, instructions, custom_env, custom_args, model, thinking_level, mcp_config, visibility, max_concurrent_tasks |
UpdateAgent rejects custom_env | 910–913 | if custom_env present in body → 400 "use PUT /api/agents/{id}/env (or multica agent env set)" |
UpdateAgent persists / clears mcp_config | 944–948, 1060–1061 | Tri-state from the raw body: key omitted → no change; literal null → ClearAgentMcpConfig; object → replace. No 400 like custom_env — mcp_config IS updatable here |
description ≤ 255 on update too | 921–924 | same cap re-checked on update |
Env endpoint — server/internal/handler/agent_env.go
| Contract | Line | Behavior |
|---|---|---|
authorizeAgentEnv gate | 66 | loads agent, then applies the two checks below |
| Agent actors denied | 80–84 | if actorType == "agent" → 403 "agents may not access env management endpoints" (MUL-2600 impersonation guard) |
| Owner/admin only | 86 | requireWorkspaceRole(..., "owner", "admin") |
Routes — server/cmd/server/router.go
| Contract | Line | Behavior |
|---|---|---|
GET /env | 603 | h.GetAgentEnv (plaintext read, gated) |
PUT /env | 604 | h.UpdateAgentEnv (full-map overwrite, gated) |
Claim-time injection — server/internal/handler/daemon.go
| Contract | Line | Behavior |
|---|---|---|
| Fresh agent re-read on claim | 1109–1111 | GetAgent(task.AgentID) — claim uses persisted fields, not create output |
| Workspace skills FIRST | 1115 | skills := h.TaskService.LoadAgentSkills(...) |
| Built-ins appended | 1116 | skills = append(skills, h.TaskService.BuiltinSkills()...) |
| Runtime payload | 1130–1143 | TaskAgentData carries Instructions, Skills, CustomEnv, CustomArgs, Model, ThinkingLevel, McpConfig (1130–1131, 1140) — confirms these are runtime-consumed; description, visibility, and max_concurrent_tasks are absent (not runtime-prompt fields) |
Skill loading — server/internal/service/task.go
| Contract | Line | Behavior |
|---|---|---|
LoadAgentSkills | 1685 | ListAgentSkills + per-skill ListSkillFiles → content + supporting files for execution |
Built-in skills — server/internal/service/builtin_skills.go
| Contract | Line | Behavior |
|---|---|---|
go:embed builtin_skills | 10–11 | skills embedded at compile time |
loadBuiltinSkill | 45 | reads <name>/SKILL.md (47) + walks sibling files into Files (56–68) |
Persisted columns — server/pkg/db/generated/agent.sql.go
| Contract | Line | Behavior |
|---|---|---|
CreateAgent INSERT | 730–736 | columns include runtime_config, runtime_id, instructions, custom_env, custom_args, mcp_config, model, thinking_level |
CreateAgentParams | 739–756 | typed params: RuntimeConfig []byte, Instructions string, CustomEnv []byte, CustomArgs []byte, Model pgtype.Text, ThinkingLevel pgtype.Text |
UpdateAgent SET | 2552–2566 | COALESCE updates of runtime_config, instructions, custom_env, custom_args, model, thinking_level — note custom_env is COALESCE-guarded but the handler rejects it before this query runs |
UpdateAgentCustomEnv (called by the UpdateAgentEnv handler) | 2652 | SET custom_env = $2 — the only write path for env values |