This repository is for maintainers working on the Portfoliable toolchain itself.
This is not the end-user manual. End users should follow the short guide in create-portfoliable/templates/README.md.
To get to know Portfoliable, please visit the official Portfoliable website
- 1. Project purpose
- 2. Key paths
- 3. Local workflow
- 4. Runtime and template source-of-truth
- 5. Thumbnail catalog maintenance
- 6. Valence integration
- 7. Protected cases and security
- 8. Release and governance
- 9. SEO and sharing rules
- 10. Required validation before merge
This monorepo contains the canonical Portfoliable implementation used by:
- the initializer package:
create-portfoliable - the generated consumer app runtime
- the template files copied into new projects
- the docs and release automation for the product
create-portfoliable/— initializer and generated app runtimecreate-portfoliable/bin/— initializer entrypointscreate-portfoliable/cli/— runtime CLI dispatchercreate-portfoliable/src/— runtime app logic and parsercreate-portfoliable/scripts/— validation, scaffolding, and release helperscreate-portfoliable/templates/— files copied into generated portfoliosweb/— marketing and docs site for end users.github/workflows/— release and deployment automation
Install dependencies from the repo root:
npm installCommon maintainer commands:
npm run validate:content
npm run build
npm run preview
npm run smoke:initializer
npm run smoke:packed
npm run smoke:homeview
npm run verify:integrationThe canonical package implementation lives in create-portfoliable/, while the generated consumer app copies files from the templated source.
Important rule:
- do not treat the generated app as the canonical runtime source
- keep template files aligned with runtime behavior when the contract changes
Inspect supported device tuples:
npm run portfoliable-thumbnail-options
npm run portfoliable-thumbnail-options -- --full
npm run portfoliable-thumbnail-options -- --jsonThis writes the generated selector map under:
create-portfoliable/templates/src/content/thumbnail-options.generated.json
Selector structure:
thumbBrand -> thumbCategory -> thumbModel -> thumbColor
Maintainer considerations:
- normalize folder names and ignore generic wrapper labels such as
device,open,closed,with bands, andwithout bands - keep naming stable for selector consistency
- verify generated tuples before using them in case metadata
Maintainers may need to link or switch between local Valence work and the published npm package:
npm run valence:status
npm run valence:local
npm run valence:npmUse these when validating new device assets or runtime UI changes that depend on local Valence edits.
Protected cases are supported through a server-side unlock flow. Do not put raw secrets in markdown files.
Use:
public/api/unlock-case.phppublic/api/password.config.jsonpublic/api/.htaccessscripts/generate-password-hash.mjs
Security rules:
- keep password config outside git
- deny direct access via
.htaccess - keep unlock responses non-cacheable
Release automation and governance live in the repository root workflow and package orchestration logic:
.github/workflows/create-portfoliable/scripts/
For product changes, update docs and behavior changes in the same PR.
This repository defines normative release behavior for the create-portfoliable package.
Policy goals:
- deterministic semantic version selection from commit history
- reproducible package publish and tagging behavior
- minimal manual intervention during standard release flow
- security-first publishing with provenance and trusted identity
Scope of release decisions:
- release computation currently evaluates changes in
create-portfoliable/as the canonical releasable package scope - changes outside that scope may still pass CI but do not contribute to version bump decisions
Commit classification rules:
- major: header contains
!or commit body containsBREAKING CHANGE: - minor:
feat: - patch:
fix:,perf:,refactor:,chore:,docs:,style:,test:,build:,ci: - non-releasable: anything else that does not match recognized conventional commit patterns
Version selection algorithm:
- resolve the latest relevant tag baseline
- compute the commit range from baseline to current head
- filter commits by release scope
- classify each commit by release impact
- select the highest impact level in range
- skip release when no releasable commits remain
Priority ordering is:
- major
- minor
- patch
Mutation rules during release:
- when release is approved and not dry-run, automation may update version metadata, prepend changelog content, create a release commit, create and push tags, and publish the npm package
- no mutation should occur when no releasable commit is present
Dry-run rules:
- dry-run mode must not write files, create commits, create tags, publish packages, or deploy Pages artifacts
- dry-run exists for planner and workflow verification only
Publishing rules:
- npm.org publishes the canonical unscoped
create-portfoliablepackage with trusted identity and provenance - GitHub Packages publishes the same version and payload under the required
@portfoliablejs/create-portfoliablealias - each registry is an explicit publish target; publishing to GitHub Packages does not mirror a release to npm.org
- the npm.org publish command includes
--provenance - long-lived credential strategies are discouraged by default
- publish and tagging only proceed after validation gates succeed
Required documentation updates for policy changes:
- any change to classification, scope logic, trigger semantics, actor gates, or publish sequencing requires synchronized documentation updates in this README and related maintainer guidance
Exception handling:
- explicit rationale
- bounded lifetime
- owner assignment
- removal plan after normalization
Exceptions are temporary and must not quietly redefine baseline policy.
This repository uses a single package-release workflow for the npm package alongside a separate web deployment pipeline.
Automation objectives:
- preserve deterministic release decisions
- keep publishing secure with provenance
- minimize manual intervention
- provide observable outputs for triage and rollback analysis
Core implementation assets:
- workflow definition:
.github/workflows/release.yml - release planning logic:
create-portfoliable/scripts/release-orchestrator.mjs
Trigger model:
pushtomainworkflow_dispatchwith optional dry-run validation
Current job topology:
- release job: checkout full repo history and tags, install dependencies, validate/build, compute the release plan, create one canonical tarball, push the release commit and tag atomically, publish to npm.org, publish its scoped alias to GitHub Packages, and create the GitHub release
- GitHub Packages sync: a manual recovery mode that copies one existing npm.org version to GitHub Packages without changing versions, commits, tags, or GitHub releases
- Pages deploy job: separate web deployment flow only for web content
Orchestrator responsibilities:
- select baseline tag
- compute in-scope commit range
- classify commit semantics
- select highest release impact
- emit release metadata for workflow steps
When release conditions are met and run mode allows mutation, the orchestrator updates version metadata and changelog, then creates a release commit and tags.
Security model:
- workflow permission includes
id-token: write - npm.org publish includes provenance flags and uses the npm trusted publisher mapping
- GitHub Packages publish uses the workflow
GITHUB_TOKENwithpackages: write - trusted publisher mapping on npm must match owner, repo, and workflow identity
Token-based fallback should be avoided unless explicitly required for exceptional recovery.
Publishing transition status:
create-portfoliable@1.0.3was published during migration while org-controlled trusted publishing was being aligned.- starting with
1.0.4, releases are expected to be published by theportfoliablejstrusted publisher mapping forrelease.yml. - keep
1.0.3available for compatibility; do not rewrite its history unless a security incident requires that action. - local manual
npm publishis incident-only and must not be used for normal releases.
Registry identities:
- npm.org:
create-portfoliable, used bynpm create portfoliable@latestandnpx create-portfoliable - GitHub Packages:
@portfoliablejs/create-portfoliable, required because GitHub's npm registry only accepts scoped packages - the workflow changes the package name only in an extracted temporary artifact; the checked-in package name remains
create-portfoliable
GitHub Packages recovery:
- Open the
Release create-portfoliableworkflow and choose Run workflow. - Enter the existing npm.org version in
github_package_version. - The workflow verifies that version on npm.org and publishes only the missing scoped GitHub Packages alias.
- Leave
github_package_versionempty for normal release planning or dry-run behavior.
Tagged npm release recovery:
- Use this mode only when the release commit and
v<version>tag reached GitHub but npm.org did not receive the version. - Run the workflow with that version in
npm_package_version. - The workflow rebuilds the canonical tarball from the existing tag, publishes any missing npm.org and GitHub Packages versions, and creates the GitHub release if it is missing.
- Set only one of
npm_package_versionorgithub_package_versionin a recovery run.
The first GitHub Packages version may require an organization owner to change package visibility from private to public in package settings. Keep the package connected to portfoliablejs/portfoliable and inherit repository access.
Validation gates before release-affecting changes are merged:
npm run validate:content
npm run smoke:initializer
npm run smoke:packed
npm run smoke:homeview
npm run buildWhen an integration environment exists:
npm run verify:integrationTypical failure modes and signals:
- no releasable commits
- expected when no conventional releasable commit/scope is detected
- npm
E404- often reflects scope, trust mapping, or package access mismatch
- npm
ENEEDAUTH- indicates authentication drift from the trusted OIDC flow
- push/tag failure
- often permission, branch protection, or a new
maincommit arriving during release planning
- often permission, branch protection, or a new
- skipped Pages deploy
- usually dry-run behavior or failed upstream artifact stage
- GitHub Packages
E404- often indicates package scope, repository access, or
GITHUB_TOKENpermission drift
- often indicates package scope, repository access, or
- npm.org succeeded but GitHub Packages failed
- rerun the workflow with the released version in
github_package_version; do not create another npm version or publish locally
- rerun the workflow with the released version in
- release tag succeeded but npm.org failed
- rerun the workflow with the tagged version in
npm_package_version; the recovery path is idempotent across both registries
- rerun the workflow with the tagged version in
Observability and diagnostics:
- workflow URL and run ID
- job IDs and failing step stage
- orchestrator outputs (
released_any,released_package, version/tag) - npm error code and raw log context
- run mode (release, dry-run, GitHub Packages sync, or tagged release recovery)
- actor and branch context
This runbook is the operational guide for release and deployment incidents.
Incident goals:
- restore safe delivery behavior quickly
- preserve traceability for root cause analysis
- avoid ad hoc manual mutations that obscure release history
Fixed triage order:
- release planner outputs
- npm publish logs
- commit/tag push logs
- GitHub release creation logs
- Pages deployment logs
Immediate triage checklist:
- capture workflow run URL
- capture branch and actor identity
- capture run mode (normal or dry-run)
- capture orchestrator outputs
- capture first failing step and full error code or message
Symptom playbooks:
Interpretation:
- planner likely behaved correctly and skipped mutation or publish
Checks:
- commit messages follow conventional format
- commit types are releasable under policy
- commits touch release scope
- baseline tag selection is correct
Recovery:
- add a new releasable scoped commit
- rerun through the normal workflow
Interpretation:
- publish reached npm but mapping or access was rejected
Checks:
- npm package scope and name are exact
- trusted publisher mapping points to the correct owner, repository, and workflow
- package access settings match publish intent
Recovery:
- correct npm mapping or access settings
- trigger release with a new releasable scoped commit
Interpretation:
- workflow authentication path diverged from trusted OIDC flow
Checks:
- workflow has
id-token: writepermission - no conflicting token-based publish overrides exist
- publish command retains provenance mode
Recovery:
- restore OIDC-based publish path
- rerun release with a fresh releasable commit
Checks:
- branch protection allows automation action
- workflow token has required permissions
- actor gate conditions are satisfied
Recovery:
- adjust permissions or gates safely
- rerun workflow
Checks:
- expected tag value exists
- release creation step received a valid payload
- API permissions are sufficient
Recovery:
- correct upstream output or permissions issue
- rerun workflow
Checks:
- run mode is not dry-run
- artifact upload succeeded
- deployment job condition evaluated true
Recovery:
- resolve artifact or condition failure
- rerun deployment path
Data to preserve during incidents:
- workflow URL and run ID
- orchestrator release outputs
- npm error code and relevant logs
- whether mutation steps executed
- remediation action taken
Recovery guardrails:
If publish failed after partial mutation:
- fix the publish root cause first
- avoid rewriting release history unless explicitly approved
- create a new releasable scoped commit
- allow the orchestrator to compute the next deterministic release step
Post-incident actions:
- document root cause and contributing factors
- identify detection and prevention improvements
- update policy, automation, or runbook docs if behavior changes
- add validation or checks that prevent recurrence
This is the shortest safe path to implement, validate, and ship changes in Portfoliable.
Preconditions:
- ensure your branch is based on
main - confirm Node.js
>=18 - run dependency installation from the repository root
npm installStandard change workflow:
- implement your change in the appropriate package path
- run mandatory local validation gates
- commit with conventional commit semantics
- open a pull request with validation evidence
- monitor release workflow outputs after merge
Normal maintainers should not run local npm publish; use the release workflow path so publish provenance and org ownership remain consistent.
Where to implement changes:
- runtime and initializer behavior:
create-portfoliable/ - root maintainer forwarding only:
cli/and root script wiring - release planning and mutation logic:
create-portfoliable/scripts/release-orchestrator.mjs - CI behavior:
.github/workflows/release.yml
Mandatory validation commands:
Run from the repository root:
npm run validate:content
npm run smoke:initializer
npm run smoke:packed
npm run smoke:homeview
npm run buildIntegration validation when the environment supports it:
npm run verify:integrationConventional commit requirements:
- major:
type!orBREAKING CHANGE: - minor:
feat: - patch:
fix:,perf:,refactor:,chore:,docs:,style:,test:,build:,ci:
Non-conventional commits are non-releasable.
Fast failure diagnosis:
- release planner outputs
- npm publish step output
- push/tag steps
- GitHub release creation step
- Pages deploy step
Why release may be skipped:
- no releasable commit in the current range
- commit did not match release path scope
- workflow executed in dry-run mode
Trusted publishing verification:
Verify npm trusted publisher mapping before deep debugging:
- package:
create-portfoliable - owner:
portfoliablejs - repository:
portfoliable - workflow file:
release.yml
Pull request checklist:
- clear summary of behavior change
- explicit risk statement
- command output from local validation gates
- documentation updates for policy or automation changes
Escalation path:
When release behavior is inconsistent with policy:
- capture workflow URL and planner outputs
- open an issue with minimal reproducible details
- link policy and automation docs sections under dispute
- apply a fix in a scoped PR with dry-run verification first
Maintainer-oriented behavior notes:
socialImageis the Open Graph and social card image, not the visible thumbnail imagevisibility.web,visibility.crawlers, andvisibility.aiare separate exposure layers- case routes, About routes, and home metadata must remain consistent with the current content contract
For runtime, parser, template, or release-impacting work, run:
npm run validate:content
npm run smoke:initializer
npm run smoke:packed
npm run smoke:homeview
npm run buildAnd when relevant:
npm run verify:integrationThis README is for maintainers and contributors. The generated-app user manual is intentionally shorter and product-focused.