From platinum-seo-engine
Use when: kullanıcı "yeni proje", "init project", "bootstrap project", "{slug} kur", "{slug} ekle", "workspace bootstrap", "yeni proje aç" der ya da /pseo-init çağırır. Also use when: pilot project workspace iskelet eksik (projects/{slug}/ yok ya da master.xlsx ve project.config.json mevcut değil); workspace- staging'de yeni bir slug ilk kez kuruluyor; idempotent re-bootstrap isteniyor (var olan master.xlsx KORUNUR, sadece config refresh). Do not use when: project zaten kurulmuş ve sadece veri ingest edilecek — sf-import, quick-wins veya başka discovery/ingestion skill kullan; mevcut master.xlsx'i schema-uyumsuz şekilde yeniden yaratmak gerekiyor — bu yıkıcı, init-project ASLA mevcut master.xlsx'e dokunmaz (F1 workbook policy + idempotency invariant).
How this skill is triggered — by the user, by Claude, or both
Slash command
/platinum-seo-engine:init-projectThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
10-step protocol that scaffolds a brand-new project pack into the
10-step protocol that scaffolds a brand-new project pack into the
workspace. Idempotent by design: re-running against an existing project
NEVER mutates master.xlsx, only refreshes project.config.json and
appends a portfolio.json entry if missing. The skill is the entry
point for every new domain; downstream Phase 6+ ingestion skills
(sf-import, quick-wins, pillar-builder) all assume init-project ran
first.
| Name | Type | Default | Notes |
|---|---|---|---|
project_slug | string | — | Required. Lowercase kebab-case; matches projects/{slug}/ dir. |
domain | string | — | Required. Project root URL (https://...). Default gsc.site_url. |
gsc_site_url | string | (= domain) | Override when GSC property URL differs from domain. |
market | string | TR | ISO 3166-1 alpha-2. |
locale | string | tr-TR | IETF BCP 47. |
profile | array | ["local-service"] | Composable project profiles (project-config.profiles enum). |
projects/{slug}/project.config.json — schema-valid project pack
config (project-config.schema.json v1.0).projects/{slug}/master.xlsx — schema-shaped workbook copied from
templates/master-excel.xlsx (lowercase logical name; F1 workbook
policy). NEVER overwritten on re-run.projects/{slug}/_state/events.jsonl — provenance event for
operation=project_excel (kind=tool_computed,
workflow_action=done).projects/{slug}/_state/workflows/{run_id}.json — workflow run state
(workflow-run.schema.json).shared/portfolio.json — append-only portfolio registry (slug,
domain, market, created_at).Step names match
steps[*].namepassed toworkflow_runner.create_run. Names are stable identifiers across runs.
project_slug must match ^[a-z][a-z0-9-]*$ (project-config.schema
pattern). domain must be a non-empty URI. Empty / whitespace / wrong
case → DURUR (do not patch, flag the manager).
create_runfrom scripts.state import workflow_runner
handle = workflow_runner.create_run(
skill="init-project",
project_slug=project_slug,
steps=[
{"name": "verify_gsc"},
{"name": "bootstrap_config"},
{"name": "copy_master_xlsx"},
{"name": "register_portfolio"},
{"name": "request_approval"},
{"name": "emit_provenance"},
],
)
The state file lives at
projects/{slug}/_state/workflows/{run_id}.json (ADR-021).
verify_gsc (optional)Skipped when gsc_site_url not supplied (or domain mode). When set,
call mcp__gsc__list_sites and assert the URL appears with at least
siteOwner / siteFullUser / siteRestrictedUser permission. If the
property is absent or auth fails, the step's output_ref records the
miss but the run continues — verification is advisory at bootstrap
time (the user may have just registered the property and propagation
is async). DURUR only if the MCP returns an auth/network error
distinct from "not present".
bootstrap_configCall the existing CLI module via subprocess (no in-process import; the
CLI's --force semantics are the contract):
python3 scripts/state/bootstrap_project.py \
--project {slug} \
--domain {domain} \
--market {market} --locale {locale} \
[--gsc-site-url {gsc_site_url}] \
[--profile {profile_i} ...] \
--out {workspace_root}/projects/{slug}/project.config.json \
--force
Validates the resulting JSON against schemas/project-config.schema.json
(Draft7) before returning. Idempotent — --force overwrites stale
config, but the file content is fully derived from inputs.
Schema version default (v1.8 Phase 1): bootstrap_project.py emits
schema_version: "1.5" by default — the SF MCP additive block
(sf.mcp.*) is included in every freshly-bootstrapped project per
D-SF-12 + D-SF-18 path parameterization. New project packs are
schema-1.5 native; no migration is invoked.
cascade_migration_0005 (safety net for legacy 1.4 docs)For projects re-bootstrapped from a pre-Phase-1 (schema 1.4) snapshot, init-project supports an explicit operator opt-in:
# Operator-side invocation (CLI):
# /pseo-init my-slug --schema-version=1.5
#
# NOTE: `--schema-version` is a SKILL / slash-command-layer flag only.
# It is NEVER forwarded to scripts/state/bootstrap_project.py — that
# CLI's argparse has no --schema-version option and would reject the
# argument. The skill layer interprets the flag and, when set, gates the
# Migration 0005 subprocess below; the bootstrap CLI is invoked (Step 4)
# without it.
#
# Inside the skill protocol: after Step 4, if the operator passed the
# explicit `--schema-version=1.5` flag AND the resulting
# project.config.json carries schema_version other than "1.5"
# (defensive: should never happen with the post-Phase-1 bootstrap,
# but guards forks/old workspaces), invoke Migration 0005 via
# subprocess:
python3 scripts/migrations/migration_0005_project_config_1_4_to_1_5.py \
--in projects/{slug}/project.config.json
# → idempotent: re-running on a 1.5 doc is a no-op (migrate() returns
# the input verbatim per migration_0005.migrate signature).
Without the flag, init-project trusts bootstrap_project.py as the
authority (current default emits 1.5). With the flag, the cascade
ensures schema 1.5 is final-state irrespective of bootstrap CLI
version. The flag is operator-controlled because cascading a
migration touches the bytes a Manager may have committed; explicit
opt-in keeps the audit trail deliberate.
copy_master_xlsx (IDEMPOTENT, F1 policy)target = workspace_root / "projects" / project_slug / "master.xlsx"
if target.exists():
# F1 + idempotency invariant: do NOT touch existing master.xlsx.
# Compute and record SHA-256 for the workflow output_ref so callers
# can audit that no mutation occurred.
output_ref = f"master.xlsx#sha256={sha256_of(target)}#preserved"
else:
template = repo_root / "templates" / "master-excel.xlsx"
if not template.exists():
raise BootstrapError("templates/master-excel.xlsx missing")
target.parent.mkdir(parents=True, exist_ok=True)
shutil.copyfile(template, target)
output_ref = f"master.xlsx#sha256={sha256_of(target)}#created"
The legacy {Slug}_MASTER.xlsx workbook (Turkish display name) is
NEVER touched by this skill. F1 (workbook policy): master.xlsx
(lowercase, schema-shaped logical sheet names) is the canonical
artifact for all new ingest flows; the display-name workbook is
read-only legacy data.
register_portfolioAppend the project to {workspace_root}/shared/portfolio.json (creates
the file + parent dir if missing). Append-only: existing entries are
preserved; only the new slug entry is added.
The append is delegated to scripts/state/portfolio_writer.register_project,
which runs the read-modify-write under a single fcntl.flock(LOCK_EX) on the
file so two parallel init-project runs cannot lose an update. The on-disk
shape is unchanged — {"schema_version": "1.0", "projects": [{slug, domain, market, created_at}, …]}, indent=2, trailing newline, ensure_ascii=False —
and re-registering an existing slug is an idempotent no-op (dedup on slug).
from scripts.state.portfolio_writer import register_project
register_project(
workspace_root,
project_slug,
domain,
market,
created_at=utc_iso_z(),
)
request_approvalworkflow_runner.request_approval(
handle.run_id, project_slug=project_slug,
approver="user",
subject=(
f"Config review: project_slug={project_slug}, "
f"domain={domain}, gsc_site_url={gsc_site_url or domain}. "
"Onaylıyor musun?"
),
step_index=4,
)
Skill EXITS at this point (status=awaiting_approval). The user
replies in a fresh session; resume below.
approve → continue)workflow_runner.approve(
handle.run_id, project_slug=project_slug, approver="user",
)
emit_provenancefrom scripts.state import events_writer
events_writer.append_provenance(
project_id=project_slug,
source={"kind": "tool_computed"},
operation="project_excel",
target_excel_sheet=None, # bootstrap touches no sheet
notes="init-project bootstrap completed",
)
source.kind=tool_computed reflects that bootstrap is not an external
ingest; it is an in-process scaffolding action. target_excel_sheet
is null because master.xlsx is COPIED from a template, not written
sheet-by-sheet.
completeworkflow_runner.complete(
handle.run_id, project_slug=project_slug,
outputs={
"config_path": "projects/{slug}/project.config.json",
"master_xlsx_path":"projects/{slug}/master.xlsx",
"portfolio_entry": "shared/portfolio.json#projects[{slug}]",
},
)
All outputs.* values are STRING-TYPED artifact paths (workflow-run
schema constraint; F5 rule). Numeric counts go in events.jsonl, not
in workflow_run.outputs.
PLANNED (Phase 14) — not yet wired. The cascade auto-runner and the
cascade: brand-onboardingevent mechanism described here do NOT exist in the current codebase: no skill auto-runner consumes a cascade event, andinit-projectreaches terminalstatus=doneat Step 10 with no downstream gate. This section documents the INTENDED Phase-14 behavior, mirroringbrand-onboarding's own staging→canonical deferral framing.
Once the cascade auto-runner exists (Phase 14), after Step 10 emits
complete init-project will emit a cascade: brand-onboarding event to
_state/events.jsonl; the auto-runner will pick it up and invoke
brand-onboarding with the freshly scaffolded project slug, whose 3-stage
bank-seed pipeline (Stages A + B + C) populates
content_settings.experience_database and
content_settings.original_research_database.
Planned completion gate (Phase 14, once the cascade is live): init will not be considered "complete" until brand-onboarding Stage C writes successfully —
Today (pre-Phase-14): Step 10's complete IS terminal — there is no
cascade emission and no completion gate. Bank seeding is a separate,
operator-initiated brand-onboarding run. The paired test
(tests/skills/test_init_project.py) asserts this terminal-done
contract.
Why this cascade is planned: the May 2026 Core Update emphasizes "original, helpful, people-first content" and penalizes "automated, ad-bloated, repetitive content". Empty banks (the pre-Phase-3 default state of all 9 projects) trivially pass R-105 / R-114 / R-119 — the rules require entries to be USED but existing skills produce empty-bank content silently. Bank seed is therefore prerequisite to E-E-A-T "Experience" depth signal.
Re-running init-project against an existing project MUST satisfy:
master.xlsx SHA-256 unchanged (file bytes preserved verbatim).project.config.json is regenerated from current inputs (so config
evolution is supported), but the Excel artifact is sacred.shared/portfolio.json gains AT MOST one new entry; duplicate slug
inserts are no-ops._state/workflows/{run_id}.json is created (each invocation
gets its own audit trail; old runs are not amended).Stop and flag the manager — do not patch, do not fall back.
project_slug invalid (fails ^[a-z][a-z0-9-]*$, contains spaces
or special chars).bootstrap_project.py CLI exits non-zero (validation/IO error).templates/master-excel.xlsx missing — cannot bootstrap workbook.workflow_runner.create_run fails schema validation
(workflow-run.schema.json).PSEO_WORKSPACE_ROOT env var unset AND no explicit workspace_root
passed.master.xlsx would be mutated
(caller passed --force or template differs and writer attempted
overwrite). The skill must abort before touching the file.schemas/skill-frontmatter.schema.json (this file's
frontmatter contract), schemas/project-config.schema.json (the
config artifact), schemas/master-excel.schema.json (the workbook
shape — referenced by templates/master-excel.xlsx),
schemas/workflow-run.schema.json, schemas/events.schema.json,
schemas/portfolio-config.schema.json (Phase 14+ richer portfolio).scripts/state/bootstrap_project.py (CLI),
scripts/state/workflow_runner.py (state machine),
scripts/state/events_writer.py (provenance),
scripts/state/portfolio_writer.py (portfolio registry, flock-guarded),
scripts/excel/bootstrap_excel.py (template generator).templates/master-excel.xlsx.tests/skills/test_init_project.py (5 cases; idempotency,
schema validity, GSC verify, provenance, portfolio registry).npx claudepluginhub popiliadam/platinum-seo-engine --plugin platinum-seo-engineUse when: kullanıcı "yeni proje", "brand onboarding", "proje bootstrap", "wizard çalıştır", "yeni site ekle", "project-config oluştur" der ya da /pseo-brand-onboarding çağırır; brand_identity 20 + content_settings 14 + profile enum 5-value Süleyman input'u alarak project-config.schema 1.5 conformant staging output üretir. Also use when: workspace henüz yok (Phase 14 öncesi staging-only mode); domain DNS doğrulanması gerekiyor; profile heuristic suggest fallback istendi; init-project çalıştırılmadan önce config wizardı isteniyor. Do not use when: mevcut proje config update için (separate edit-config skill — gelecek phase); workspace var ve direkt project.config.json yazılacak (Phase 14+ behavior; init-project devreye giriyor); başka projenin config'i kopyalanacak (template-clone — gelecek phase).
This skill should be used when the user wants to start a new project-portfolio for partner project-portfolio steering — cogni-projects models consultants, projects, and staffing, so new portfolio work starts here. Trigger on: "set up a projects portfolio", "start a project portfolio", "new cogni-projects portfolio", "initialize project-portfolio steering", "create a staffing portfolio", or any request to begin structured consultant/project/staffing work — even if the user does not say "setup" explicitly.
Initializes an Agentic SEO project with standard directory structure, blank brain templates, content scaffolding, and first log entry. Use when creating or resetting the project.