Install
$ agentstack add skill-shalintripathi-organic-os-setup ✓ scanned · ✓ verified, works with Claude Code, Cursor, and more.
Security review
✓ PassedNo issues found. Passed automated security review. · v0.1.0 How review works →
- ✓ Prompt-injection patterns
- ✓ Secret / credential exfiltration
- ✓ Dangerous shell & filesystem operations
- ✓ Untrusted network calls
- ✓ Known-malicious package signatures
What it can access
- ● Network access Used
- ✓ Filesystem access No
- ✓ Shell / process execution No
- ● Environment & secrets Used
- ✓ Dynamic code execution No
From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.
Verified badge
Passed review? Show it. Paste this badge into your README, it links to the public security report.
Reliability & compatibility
Declared compatibility
Compatibility is declared by the source manifest. End-to-end runtime verification is coming, see below.
We're building live execution health for every listing: tool-call success rate, median latency, uptime, and last-checked timestamps, measured, not self-reported. It isn't live yet, so we don't show numbers we can't stand behind.
How agent discovery & health will work →About
organic-os setup
You are onboarding or managing sites in organic-os. Everything site-specific comes from this interview or the audit that opens it - never invent a value without surfacing it for the user to approve or edit, and never ask a question the audit already answered. One question at a time, AskUserQuestion with options where possible.
Two claims matter and they are not the same: "configured" (an answer was recorded) and "verified working" (a live probe proved it). Setup collects both, but only ends on the second - see Postflight scorecard.
Interview style (every mode, every question)
- One question at a time. Never present a wall of questions. Ask, wait
for the answer, then ask the next one.
- Offer a default with every question. State it plainly ("default: none
- press enter to skip") so the user can move fast when they do not care.
- Choice questions are chips. Every question with a finite option set -
quick-start vs full setup, approval channel, runtime, brain mode, every connector wizard decision - goes through the AskUserQuestion tool with options, which renders native multiple-choice chips in both Claude Code and Cowork (free-text "Other" included automatically). Mark the recommended option "(Recommended)" in its label so the sensible default is one click. Free text is reserved for values that are genuinely free text: the site URL when the install form did not carry it, brand voice notes, operator knowledge.
- Install-form answers are pre-answered questions. Anything Step 0.75
found is never re-asked, in any mode - state where the value came from and move on.
- Secrets are referenced, never echoed. Confirm a form-provided
credential as "found the WordPress Application Password from the install form" - the value itself never appears in chat, in a summary table, or in any file except the site env file.
- Show progress. Prefix each question with where the user is - e.g.
"question 3 of roughly 10" for the full setup interview (count whatever this run will actually ask: reviewing/editing the proposed profile, operator knowledge, editorial rules, Google Ads, WordPress, approval channel, runtime, brain path, brain mode - the connector wizard runs as its own probe-and- verify flow and is not counted in this total), "question 2 of 3" for quick-start, "question 1 of 2" for a targeted update-mode re-ask.
- End with a summary table. After the last question and the scaffold/
write actions, print a table of what was written and where (file path, field, value) so the user can see the whole result of the interview in one place before they move on. The postflight scorecard (below) comes after this table, not instead of it.
Step 0: environment checks
- Confirm
python3is on PATH. - Confirm PyYAML is importable:
python3 -c "import yaml". If this fails,
tell the user to run python3 -m pip install --user pyyaml before continuing - both core.contracts and core.registry require it.
Step 0.5: where am I, where will routines run
Setup may be running in a different environment than the one routines will execute in - most commonly a cloud Cowork session setting up a local runtime that lives on the user's Mac. Work this out before touching any file, because it changes where almost everything below gets written.
- Determine the setup environment. No single signal is proof by
itself; weigh them together, and ask if still unsure:
ls ~/.config/organic-os 2>/dev/nullandtest -f ~/.claude.json-
a fresh cloud sandbox rarely carries config from a prior local run.
gh auth status 2>&1- a cloud sandbox is almost always
unauthenticated; a local CLI session the user has used before usually is not.
- macOS Keychain probe (local-only signal): `security find-generic-
password -s "Claude Code-credentials" 2>&1` - a cloud sandbox has no keychain, so this errors immediately or the command is unavailable.
- If the signals disagree or nothing is conclusive: ask plainly, "Are
you running this in a local terminal on your own machine, or a cloud / Cowork session?"
- Ask which runtime will execute routines (unless the caller already
established this): claude-scheduled | local | ci | manual - same options as the full setup interview's runtime question below. If answered here, do not re-ask it later; carry it forward.
- If setup environment and runtime location match (e.g. a local CLI
session setting up a local runtime), continue normally - every step below writes directly where it says it does.
- If they differ, say so out loud to the user before continuing, then
hold to these three rules for the rest of the session:
- **Registry and brain scaffold target the runtime location, not the
setup session.** If setup has no way to write files on the runtime machine directly (no bridge shell reaching it), do not fake success. Emit a ready-to-run snippet - one bash block covering init_site_repo.py, core.registry.register(...), and git init - for the user to paste into a terminal on the runtime machine. Record this row in the summary table as "handed off, not yet confirmed" and let the postflight scorecard be the thing that actually confirms it landed.
- **Connector probes are labeled with the context that actually ran
them.** Every core.contracts.record_connector(...) call passes the real context - cowork-cloud for a probe this session ran itself, local-cli for one the user ran locally and reported back, ci for a CI runner. A connector reachable from the setup session is not "available" for a runtime that cannot reach it - never blur the two. Say plainly that the runtime-side probe (which the postflight scorecard runs, or asks the user to run and report) is the one that actually matters for routines.
- Never run git through a device bridge. If setup is bridging
commands into the user's local machine, use the bridge only to scaffold files. git init, the first commit, and gh repo create happen natively - hand the user the exact commands and let them run in their own terminal. A bridge-proxied git init tends to write with the wrong identity or permissions, and it proves nothing about whether the runtime machine can push on its own.
Step 0.75: read the install form
Claude Code and Cowork can render a native configuration form when the plugin is enabled, declared in plugin.json's userConfig block: site URL, brand name, approval channel, Telegram bot token, WordPress Application Password, WordPress username. Every field is optional and the form may never have been shown or filled - design for both cases, and treat every value as possibly absent.
Where the values land at runtime:
- Sensitive fields (
telegram_bot_token,wp_app_password) are
stored in the OS keychain and reach this session only as environment variables: CLAUDE_PLUGIN_OPTION_TELEGRAM_BOT_TOKEN and CLAUDE_PLUGIN_OPTION_WP_APP_PASSWORD. Probe presence without printing: [ -n "$CLAUDE_PLUGIN_OPTION_WP_APP_PASSWORD" ] && echo found - never echo the variable itself.
- Non-sensitive fields substitute as
${user_config.site_url},
${user_config.brand_name}, ${user_config.approval_channel}, and ${user_config.wp_username} in plugin files, and may also be present as CLAUDE_PLUGIN_OPTION_SITE_URL, CLAUDE_PLUGIN_OPTION_BRAND_NAME, CLAUDE_PLUGIN_OPTION_APPROVAL_CHANNEL, and CLAUDE_PLUGIN_OPTION_WP_USERNAME. List names only, never values: env | grep '^CLAUDE_PLUGIN_OPTION_' | cut -d= -f1.
- Defensive rule: a value that is empty, unset, or still a literal
unsubstituted ${user_config....} string counts as "not provided" - fall through to the normal question for that field. Never fail or stall because the form was skipped; the interview covers everything the form covers.
What each present value pre-answers (never re-ask any of these):
site_url- the URL question in both modes; the audit starts from it
directly.
brand_name- replaces the domain-label guess.approval_channel- the approval-channel question (validate it is one
of in-session | telegram | slack | email | pr-merge; anything else falls back to asking, with the form's text shown as context).
wp_username+ the Application Password - the WordPress question:
confirm the endpoint from the audited URL instead of asking blind.
telegram_bot_token- the Telegram credential ask in Credentials
below; only the chat id still needs asking.
Sensitive values are referenced, never echoed back in chat: confirm as "found the WordPress Application Password from the install form" and nothing more. The audit-first flow below then fills what it can from the URL; the interview asks only the remainder.
Step 1: read the registry, pick a mode
Read PYTHONPATH="$CLAUDE_PLUGIN_ROOT/lib" python3 -c "..." calling core.registry.load() (default path ~/.config/organic-os/sites.yaml, resolved at the runtime location per Step 0.5 when it differs from the setup session).
- Registry empty (no sites): if the caller (e.g.
start) already
established which mode the user picked, go straight to that mode below. Otherwise ask first, AskUserQuestion with options:
Quick start (~2 minutes) (Recommended)- go to the quick-start
interview below. With a filled install form this is one click; with no form it is the URL plus 2 more questions.
Full setup (audit the site, then review the proposal)- go to the
full setup interview below.
- Sites exist: ask the user what they want, AskUserQuestion with options:
update- refresh the currently active site's profileadd another website- onboard a new site (full setup interview, own
brain path)
switch active site- change which site routines/commands act onshow status- print the registry (all sites, which is active) plus the
active site's site-profile.yaml summary, and the latest postflight scorecard summary line if one exists (see Postflight scorecard); no writes
Update mode
- READ the existing
site-profile.yamlfor the active site first. Present
the current values back to the user.
- Schema check: run
core.contracts.check_schema(brain_path). If
action: "stamp", the profile predates versioning - add schema_version: 1 at the top of the file, unchanged otherwise, before doing anything else, and tell the user this is the migration entry point (this is where a future major version's migration steps would run too). If compatible: false for any other reason, relay the action string and stop before re-asking anything.
- Re-ask only the sections the user picks (site, brand, editorial
rules, audience, keywords, competitors, connectors, Google Ads, WordPress, approval channel, runtime). Do not re-run the full setup interview. If the user picks "connectors," run the Connector wizard below rather than a plain available/absent question. If the user picks "WordPress" or "approval channel" and it needs a new secret, run it through Credentials below. Update mode re-asks these sections directly - it does not re-run the audit-and-propose flow, since a returning user already has a profile to edit from.
- Rewrite
site-profile.yamlwith just those changes. - Skillbook: NEVER re-append an operator note unless its text is new - read
skillbook.md first, skip anything that already matches an existing entry's text.
- NEVER touch
signals/,decisions/,reflections/, or existing
skillbook entries beyond the dedup check above - those are memory, not config, and setup does not rewrite memory.
- Do not re-register routines unless the user explicitly asks to change
cadence or runtime.
- If any of connectors, WordPress, approval channel, or runtime changed,
re-run just those rows of the Postflight scorecard (below) and show the updated table - do not force a full scorecard re-run for an update that only touched brand voice or keywords.
- Rule of thumb to state to the user: config is editable, memory is not.
site-profile.yaml and the registry are safe to change anytime; anything already written under signals/decisions/reflections/outcomes/skillbook stays as a historical record.
Add mode
Run the full setup interview below with a fresh brain path (never reuse another site's brain). After scaffolding, call core.registry.register(url, name, brain_path) - this both records the site and makes it the active one.
Switch mode
Ask which registered site (list slugs + names + urls from the registry), then core.registry.set_active(slug). No file other than the registry changes.
Show status
Print, without writing anything: every registered site (slug, name, url, brain path), which one is active, and - for the active site - whether its site-profile.yaml, skillbook.md, and approvals/queue.md exist, a one-line summary of each, and the latest postflight scorecard summary line (see Postflight scorecard) if a runs/*-setup-scorecard/REPORT.md exists.
URL first, audit before asking (shared by quick-start and full setup)
Both modes below start the same way: get the URL, then let organic-os do the looking instead of the asking. Ask only what an audit genuinely cannot answer - this is the "audit-and-propose" model: enter a URL, get a pre-filled profile to approve, instead of a wall of questions the plugin could have answered itself.
- Ask for the site URL - unless Step 0.75 already found
site_url
on the install form, in which case state it ("using https://example.com from the install form") and skip straight to the audit. When asking: no default - this is the one thing neither mode can guess. If the brand name is not obviously derivable from the domain label (a generic domain, or one that plainly does not match the brand), ask for it in the same turn; otherwise guess it from the domain label and let the user correct it during proposal review. A brand_name from the install form replaces the guess and is not re-asked either way.
- Audit before asking anything else. Fetch the homepage and
/sitemap.xml (or whatever sitemap the homepage's ` tag or robots.txt` points at instead).
- Detect the CMS: look for
wp-content/wp-includespaths, a
generator meta tag, and Yoast/RankMath fingerprints - a post-sitemap.xml/page-sitemap.xml sitemap-index shape usually means Yoast, a sitemap-pt-* shape usually means RankMath, plus either plugin's characteristic HTML comments. Record what was detected; this seeds the WordPress question later instead of asking blind.
- Read 3-5 representative pages: the homepage plus whatever the
sitemap or homepage nav suggests matters most - an about/product page, a couple of the most prominent content pages.
- Propose, from what was actually read (never invent a value - if
the audit could not reach enough pages to support a field, leave it blank and say so in the proposal rather than guessing):
- Brand voice descriptors, grounded in the actual copy (e.g. "short
sentences," "second person," "numbers up front" - whatever the fetched pages actually show, not a generic default list).
- Audience segments, from who the copy is visibly written for.
- 5-9 seed keywords, pulled from titles, headings, and repeated
topics across the fetched pages.
- 3-5 content-SERP competitors: run WebSearch on the top 2-3 proposed
keywords and take the sites that actually rank for them. State the distinction to the user plainly - these are sites competing for the same search queries, which is not the same list as business
…
Source & license
This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.
- Author: shalintripathi
- Source: shalintripathi/organic-os
- License: MIT
- Homepage: https://organicos.shivaatripathi.com
Install and usage instructions live in the source repository linked above.
Reviews
No reviews yet, be the first.
Write a review
Versions
- v0.1.0 Imported from the upstream source.