eos-orgs-create
Create a Real Org in `apps/public/standard/company/` by extracting details from the current Claude Code conversation and confirming once. Use when the user says "create an org", "new org", "add a comp
SKILL.md.claude/skills/eos-orgs-create/SKILL.md
GitHubEmptyOS Orgs — Create
Create a new Real Org under apps/public/standard/company/. Unlike the web UI's AI-form-fill modal, this skill has the current conversation as context — it should pre-fill every field it can infer from chat history, then ask the user to confirm once instead of grilling field-by-field.
The skill writes through the HTTP API (POST /orgs/api/orgs) so the vault note, frontmatter shape, and downstream events match the web UI exactly. Do not write vault notes directly — that bypasses validation + event emission.
When to Use
- User says "create an org", "new org for X", "add a company", "make a team for the Y project"
- Conversation has surfaced a real-world organisation (employer, client, side-project, study group) that's worth tracking in the system
- Not for Persona Sims — those are scenario sandboxes, created via the web UI's Persona tab
- Not for adding members to an existing org — use
eos-orgs-member-addinstead
Pre-flight
This skill writes through the daemon HTTP API, so the daemon must be reachable first:
- Daemon up —
curl -s -o /dev/null -w "%{http_code}" http://127.0.0.1:9000/orgs/should print200. If not, ask the user to runrestart.bat— never start/restart the daemon yourself (.claude/rules/daemon-handling.md). - Auth (private mode) — read
auth_tokenfromemptyos.toml[network]and sendAuthorization: Bearer <token>on every request (.claude/rules/environment.md). - Non-ASCII bodies — POST via Python
urllib, notcurl -d(Windows cp1252 mangles em-dash / CJK).
Schema (Real Org, v1)
Exactly the fields POST /orgs/api/orgs accepts. Defaults applied server-side when omitted.
| Field | Type | Required | Default | Notes |
|---|---|---|---|---|
name |
string | yes | — | Display name. Also becomes the slug-id (lowercase, hyphens). |
kind |
enum | no | team |
team / household / side-business / employer / vendor / community / other |
reality |
enum | no | real |
real (humans) or virtual (simulation — but use the web UI for these) |
scope |
enum | no | member |
member (internal) or external |
mission |
string | no | "" |
One sentence. |
vision |
string | no | "" |
One sentence. |
values |
string | no | "" |
Comma-separated or prose. |
culture |
string | no | "" |
Free-form. |
roles |
string | no | "" |
Free-form description of org chart shape. |
parent |
string | no | "" |
Parent org id, if this is a sub-team. |
company_id |
string | no | "" |
Linked org id (e.g. a division's parent company). |
Process
Step 1 — Scan the conversation for clues
Don't ask the user anything yet. Read back through the conversation (and any args passed to the skill) and extract:
- Name — explicit mentions ("Acme Corp", "the Phoenix team", "Build Club Sydney"). Pick the most-recently-named candidate if multiple appear.
- Kind —
employerfor a company you work at;side-businessfor your own venture;teamfor project / squad / sub-group inside a larger org;communityfor meetups / clubs / open-source projects;householdfor family / shared-living;vendorfor a supplier or contractor relationship;otherif none fit. - Mission / vision / values / culture / roles — pull verbatim phrases from chat if the user said things like "they focus on X" or "their roles are Y, Z". If nothing surfaced, leave blank — do not invent.
- Parent / company_id — only if the user explicitly said "this is part of <other org>" and that org already exists (run
GET /orgs/api/orgsto confirm; do not chain-create parents in one skill invocation).
If name is impossible to infer, ask the user for it directly via AskUserQuestion before continuing. Everything else is optional — leave blank rather than guess.
Step 2 — Render the proposed spec
Print a compact preview block:
Proposed org:
name: <name>
kind: <kind>
reality: real
scope: member
mission: <or "(blank)">
vision: <or "(blank)">
values: <or "(blank)">
culture: <or "(blank)">
roles: <or "(blank)">
parent: <or "(none)">
company_id: <or "(none)">
Step 3 — Confirm once
Use AskUserQuestion with three options:
- "Create as proposed" — POST the spec as-is.
- "Edit fields first" — accept inline corrections from the user, re-render, re-ask.
- "Cancel" — abort, no API call.
Do not split this into per-field questions. One confirm beats nine grills.
Step 4 — Read the auth token + POST
Read auth_token from D:\emptyos\emptyos.toml (it's the top-level auth_token = "..." under [network] or root). Pass it as a Bearer header. The skill assumes the daemon is at http://127.0.0.1:9000; if [network] port differs, read it from the same config.
TOKEN=$(grep -E '^auth_token' D:/emptyos/emptyos.toml | head -1 | sed 's/.*= *"\(.*\)".*/\1/')
curl -s -X POST http://127.0.0.1:9000/orgs/api/orgs \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '<JSON spec>'
Use python -c "import json; ..." for the JSON body if the spec contains characters that bash escaping mangles (em-dashes, unicode quotes — see memory feedback_curl_windows_utf8_bodies).
On the response:
{id, name, vault_path}→ success, capture all three{error: "..."}→ surface the error verbatim, stop the skill, do not retry blindly
Step 5 — Verify
curl -s -H "Authorization: Bearer $TOKEN" http://127.0.0.1:9000/orgs/api/orgs/<id>
The response should include the org with the fields we sent. If the GET returns 404 or {error:...}, the POST silently failed — escalate to the user with both responses so they can diagnose.
Step 6 — Report
Output to the user:
✓ Org created: <name>
id: <id>
vault: <vault_path>
edit web: http://localhost:9000/orgs/?org=<id>
Next:
• Add members → /eos-orgs-member-add <id>
• Open in web → click the URL above
Do not offer to start a /schedule, do not create follow-up tasks, do not invent next steps that aren't on the list above.
Verification (end-to-end check after skill run)
The user should see:
- The web UI at
/company/lists the new org under "Real Orgs" - The vault has a new file at
{vault}/30_Resources/EmptyOS/org/<id>/<id>.mdwith the frontmatter we POSTed - The system event log shows one
orgs:org_createdevent with payload{id, name}
If any of these are missing, the org write didn't fully land — check the daemon log at D:\emptyos\data\daemon.err.log and surface the diagnosis.
Anti-patterns
- Don't generate mission/vision/values from thin air. Blank is honest; LLM-spun corporate filler is worse than nothing and pollutes the vault.
- Don't write the vault file directly with the Write tool. The HTTP path emits events; direct writes are invisible to the rest of the system.
- Don't pre-create a parent org "to satisfy the schema". Parent must already exist; if it doesn't, leave parent blank and let the user wire it up afterwards.
- Don't use this skill for one-shot scenarios (planning meetings, ideation sims). Those belong in the web UI's Persona Sim tab — they're throwaway by design.