Your professional identity as code. A forkable data workspace for the profile-as-code engine: facts live in YAML, per-platform texts are rendered from them, and one source of truth keeps every profile consistent.
This repository is a template, not the engine. It contains no application code. You copy it, replace the fictional example with your own facts, and the engine validates and renders the result.
| You want… | It lives in |
|---|---|
| This workspace layout, docs, CI | this repo |
The pasco CLI, the schema, the renderers |
profile-as-code |
schema/profile.schema.json |
engine schema |
The engine SPEC (§9 covers this template) |
engine docs/SPEC.md |
| Prior art / research notes | engine docs/research/01-prior-art.md |
- Scaffold v0.3.2, tracking
@profile-as-code/cli@0.3.7— the currentlateston npm, verified 2026-10-31 ([OFICIAL] [WEB: registry.npmjs.org])..pascorcdeclares"engine": "0.3.7"— the floorpasco doctor,validate,buildandpreviewenforce from 0.3.7 on. A CLI older than that does not read the key at all: it applies its own rules and renders a tree this scaffold does not document, so pin the install as the commands below do. - The example content is a fictional persona (Alex Rivera) that documents the
schema — the answer surface (
identity.definition,faq[]), the registry reference (projects[].artifactRefs) with the two facts it sits next to (nationalityv1.13,publication.kindv1.14) and the release event (releases[]), up to v1.15. Do not put real data in this repository; your data belongs in your fork. - Maintained on a best-effort basis. Issues and PRs are triaged; see CONTRIBUTING.md.
A profile is published in many places and each one drifts. This workspace makes the facts the source of truth:
- Facts (dates, roles, projects, papers, DOIs) are deterministic, validated, and drift-checked — an LLM cross-referencing your profiles must find the same facts everywhere (GEO consistency).
- Texts (headlines, bios, angles) are generated per platform and per language
(
enessential,esnative;fris desirable), in variants you choose. - Evidence is a first-class registry: claims, third-party credentials, and artifacts are different things and are named as such.
- Deploy is tracked: a ledger records what was pasted where, and whether it
is still in sync with
content/.
Privacy rule #0: create the repository private before you write a single fact. A public profile-data repo exposes your contact details, history and media. The CLI path below creates it private in one step.
-
Create your workspace from the template, private:
gh repo create profile-data-<username> \ --template ChristianLuciani/profile-data-template \ --private
Manual alternative: Use this template (or fork) on GitHub, then rename it to
profile-data-<username>and make it private. The name carries the owner and the family prefix (canonical naming, engine SPEC §9.1). -
Clone it:
git clone git@github.com:<your-user>/profile-data-<username>.git cd profile-data-<username>
-
You do not need to install the engine to get output. In your copy,
.github/workflows/build.ymlinstalls the pinnedpascofrom npm and commits the generatedprofiles/on every push tomainthat touchescontent/. Editcontent/in GitHub's web editor and the views appear.Confirm Actions is enabled in your copy. You do not need to change Settings → Workflow permissions: the workflow declares its own
contents: write. Check the Actions tab after the first push.For local runs, Node 22+ is required (engine
engines):npm i -g @profile-as-code/cli@0.3.7
-
Replace the example in
content/with your facts. Each file is its root property —bios.yamlis thebios[]array directly, with no wrapper key (schema):identity.yaml— name, location, canonical links (the SSOT for your URLs),definitionandnationality(v1.10 / v1.13)positioning.yaml— positioning statement, audience angles, GEO anchorsbios.yaml,headlines.yaml— per platform, language and lengthskills.yaml,experience.yaml,projects.yaml,publications.yaml,keywords.yamlfaq.yaml— the citable answer pairs behind theFAQPageblock (v1.10)releases.yaml— release events and the presence fan-out (v1.15)
-
Validate and build:
pasco doctor # engine · schema · workspace valid · .pascorc requirement met pasco validate # schema FAILS (exit 1); drift/GEO WARN (exit 0) pasco check # offline gate: registry (M7/§18.8), media transport (M8/§18.6), # limits and fact-present over the built surfaces pasco build # deterministic per-platform output (no arg = all) pasco preview # one self-contained HTML page in .pasco/preview (not a publication) pasco diff # changes since the last release tag → CHANGELOG pasco refine linkedin # PARTIAL: emits an agent task; --choose records the pick pasco status # per-entry: origin · surfaces · in-sync/stale/never pasco status --write-checklist # regenerates CHECKLIST.md from the ledger
-
Deploy. Paste each generated text into its platform (see CHECKLIST.md), or let git/API update your GitHub README and site. Record each paste so the ledger knows what is live:
pasco status --mark experience:exp-example-labs linkedin # writes deployedAt + contentHash to content/deployments.yaml — only pasco writes it -
Version. Every change ships with a
CHANGELOG.mdentry, so you know what to re-paste and where.
The engine writes only when writing is the command's job, and only where you ask it to. No reading command rewrites your facts as a side effect:
| Command | Writes |
|---|---|
pasco build |
profiles/<platform>/ (+ bundled assets/) — derived, committed |
pasco refine --choose |
content/active.yaml — the variant you picked |
pasco edit <contract-path> --set |
that one field in content/*.yaml (comment-preserving, validated, atomic) |
pasco status --mark |
content/deployments.yaml — the deploy ledger (D18) |
pasco status --verify |
certification in content/deployments.yaml (the one opt-in network path) |
pasco status --write-checklist |
CHECKLIST.md — AUTO-GENERATED view of the ledger |
pasco preview |
.pasco/preview/ (gitignored), or the --out directory you name |
pasco export … --out, pasco entity --jsonld --out |
only the path you pass to --out; --check and export profile --json write nothing (they print) |
pasco post seed/task/choose/import |
posts/<id>/… — only if you use the MVP post flow |
profiles/ is generated output and is committed in your workspace: it is the
deploy artifact. Never hand-edit it — fix content/ and rebuild. This template
is the exception: its build.yml bot refuses to commit output there
(is_template — see the build row below and profiles/README.md). .pasco/ is
local state and is gitignored.
| Concept | Block | It is | Example |
|---|---|---|---|
| Claim | projects[].evidence[] |
a textual assertion + source | "raised $2M" → TechCrunch link |
| Credential | content/credentials.yaml |
a third-party attestation | AWS cert, degree, award, patent |
| Artifact | content/artifacts.yaml |
a work or media item | portfolio, showreel, dataset, code |
publications[] and press[] keep their own blocks and reference registry
ids via artifactRefs; they are not registry kinds. (press[] is a brand
flavor block; this template ships flavor: person, so a write-up about you is
an artifact of kind: document or a claim. See
docs/evidence-packs.md.)
A reference to an id that does not exist fails the load (dangling cross-ref,
exit 1) — it is not silently ignored.
visibility: public | unlisted | private (absent = public). Only public
counts as public. unlisted and private are treated the same by the gate:
neither can be referenced from public output, and neither is emitted in renders.
pasco check fails the build if public material references one.
media/ holds small, versionable binaries. A path locator is the source of
truth; the renderer bundles it into profiles/<platform>/assets/ with a
sha256 manifest, and the deployed output links a deploy-relative
assets/<id>/<basename>. Never hot-link a file from a private repository: for
the rest of the world it is a 404.
Limits and tradeoffs: media/README.md, docs/power-user-symlinks.md.
profile-data-<username>/
├── content/ # YOUR data (YAML)
│ ├── credentials.yaml # third-party attestations (optional, D17/§18)
│ ├── artifacts.yaml # works and media (optional, D17/§18)
│ ├── faq.yaml # citable Q&A pairs / FAQPage (optional, v1.10)
│ ├── releases.yaml # release events + presence fan-out (optional, v1.15)
│ └── deployments.yaml # deploy ledger (written only by pasco status --mark)
├── media/ # small versionable binaries (optional, §18.6)
├── docs/ # evidence packs · symlink/stow tradeoffs · standards
├── profiles/ # generated deploy artifacts (committed, never hand-edited)
├── .github/ # CI, link/secret/example-data gates, issue templates
├── .pascorc # CLI config: workspace, defaults, diff.tagPattern, engine
├── CHECKLIST.md # per-platform post-deploy verification (EN · .es)
└── CHANGELOG.md # every change: date + what to re-paste
Six checks plus the build job. All actions are pinned by full commit SHA; Dependabot keeps the pins current.
| Workflow | Trigger | What it does |
|---|---|---|
checks.yml → yaml |
push to main + every PR | content/*.yaml parses |
checks.yml → pins |
same | every mention of @profile-as-code/cli in a workflow or local action is exactly the .pascorc → engine version (a whitelist of strings, not a command detector), with a four-probe self-test — the pin has one source |
checks.yml → links |
same | relative markdown links resolve, plus a self-test that the gate rejects a broken link |
checks.yml → example-data |
same | content/ is still fictional, media/ still empty, no local state tracked |
checks.yml → secrets |
same | gitleaks (pinned CLI + SHA-256) scans the full history |
checks.yml → evidence |
same | pasco validate + pasco check (the §18.8 gate) |
workflow-lint.yml |
workflows change | every workflow file parses — kept separate so it can cover checks.yml itself |
build.yml |
push to main touching content/**, .pascorc, the link script or itself |
validate + check + build; commits profiles/ in a user workspace and refuses here (is_template, fail-closed) |
The example-data job runs only in this template repository — a fork
legitimately carries a real identity, so the guard skips there (running it in a
fork would fail on every PR).
The build job is the only one with contents: write. In user workspaces it
commits the generated output as github-actions[bot]; in this template it
refuses (the is_template check is fail-closed: a missing flag aborts instead of
pushing blind). Its push uses GITHUB_TOKEN, so it triggers no workflow — that is
why it runs the link gate itself, through the same
.github/scripts/check-links.sh used by checks.yml.
- No real data in this repository.
content/is a fictional example andmedia/ships empty; CI fails here if that stops being true (the guard skips in forks, where real data is the point). - Never paste real profile data, tokens or private media into an issue or PR. This repo is public; your workspace is not.
- Security reports go through GitHub privately, never a public issue: see SECURITY.md.
- Forking is your responsibility. Create the fork private, keep the engine pinned, and review dependency updates before merging them.
- Local state that may contain machine paths (
.pasco/) is gitignored.
Contributions are welcome when they help every user of the family, not one person's data. Start with CONTRIBUTING.md; the Code of Conduct applies. Open an issue before a large feature; bugs and proposals have issue templates.
Versions mirror the engine pin: MAJOR.MINOR is the engine line, PATCH is this
scaffold's revision. v0.3.2 is the current release (engine 0.3.7);
v0.3.0 was the first tagged release. Tagging, the re-sync of a fork, and the
list of files that must be bumped together are in
CONTRIBUTING.md § Releases.
| Symptom | Cause / fix |
|---|---|
pasco: command not found |
Install it (npm i -g @profile-as-code/cli@0.3.7) or run npx -y @profile-as-code/cli@0.3.7 <cmd> |
doctor exits 1, or validate/build refuse with an engine requirement |
The installed pasco is below the engine floor in .pascorc — install at least that version (an older CLI ignores the floor) |
validate fails on dangling cross-ref |
A credentialId / artifactId / artifactRefs points to an id that does not exist |
check fails on private-in-public-output |
A public claim references an unlisted/private entry — make it public or drop the reference |
| The build bot commits nothing | Confirm this is a user workspace (not the template), Actions is enabled, and the push touched one of the watched paths |
A workflow dies in 0s (startup_failure) |
A YAML error in that workflow. workflow-lint.yml exists for exactly this class and parses the files in CI |
| Generated README links 404 | assets/ was not committed with the output, or the link is not deploy-relative |
The scaffold follows the engine's milestones; the current line is engine 0.3.x.
Priorities and open work live in issues
and in the engine's roadmap. pasco check executes the registry and media rules
today; the remaining declarative catalog ships with engine M3/M4.
MIT. When you fork this template for your own workspace, replace the
Copyright (c) line in LICENSE with your name.
- Engine: https://github.com/ChristianLuciani/profile-as-code
- Engine spec: https://github.com/ChristianLuciani/profile-as-code/blob/main/docs/SPEC.md
- Schema: https://github.com/ChristianLuciani/profile-as-code/blob/main/schema/profile.schema.json
- Roadmap: ROADMAP.md
- Prior art: https://github.com/ChristianLuciani/profile-as-code/blob/main/docs/research/01-prior-art.md
- Media pipeline: https://github.com/ChristianLuciani/profile-as-code/blob/main/docs/media-pipeline.md