Before starting work, read how to claim an issue and submit a PR.
Issues labeled in-progress or assigned to someone are not available to claim.
PortOS is a highly opinionated, personal project — a single developer's "everything app," built and maintained for that developer's own machine and workflow. It's MIT-licensed and open to the public, but it is not built or governed as a general-purpose open source project: there's no roadmap vote, no maintainer team, and no commitment to stability for anyone else's deployment. Read this before opening a PR so expectations are clear going in.
- The project prioritizes the author's own needs first. A PR that's a great idea in the abstract may still be declined or reworked if it doesn't fit how the author actually uses PortOS.
- Breaking changes ship without warning. There's no deprecation cycle for external consumers. If you're running a fork, expect to reconcile changes yourself on each pull.
- Small, focused PRs are far more likely to land than large ones. If you're proposing a new feature area rather than a fix, consider opening an issue first to check it's a direction the project wants, before investing significant time.
- Bug fixes, docs corrections, and small quality-of-life improvements are the easiest path in.
Choose the PostgreSQL backend before running npm run install:all: install and start Docker with Compose for the default Docker backend, or set PGMODE=native in the repository-root .env for a fresh native install. Preserve existing settings and check for a conflicting exported PGMODE. Existing installs must retain the backend holding their records; see SETUP.md before changing it.
# Clone and install
git clone https://github.com/atomantic/PortOS.git
cd PortOS
npm run install:all
# Start development, including Vite on :5554
npm run devnpm run dev executes scripts/dev-start.js to initialize PostgreSQL, stop any existing PM2 processes, and start the full development process set defined in ecosystem.config.cjs (portos-server, portos-cos, portos-ui, portos-autofixer, portos-autofixer-ui, portos-browser) while tailing logs.
PostgreSQL is a mandatory dependency — the server fails fast at boot without a healthy database. npm run install:all runs npm run setup:db, which provisions either the system PostgreSQL (:5432) or a Docker container (:5561, via docker-compose.yml). See STORAGE.md and the Postgres ADR.
For DB-backed tests, provision the separate test database first (npm run setup:db:test) and run them via npm run test:db — never against the real portos database.
- Favor functional programming over classes
- Keep code DRY (Don't Repeat Yourself)
- Follow YAGNI (You Aren't Gonna Need It)
- Use functional components and hooks
- Use Tailwind CSS for all styling
- No
window.alertorwindow.confirm- Use inline confirmation components or toast notifications - Linkable routes for all views - Tabbed pages, sub-pages, and forms should have distinct URL routes for bookmarking/sharing
// Good - linkable routes
/devtools/history
/devtools/runner
/devtools/processes
// Bad - state-based tabs (not linkable)
/devtools (with local state for active tab)- Use Zod for request validation
- No shell interpolation - use spawn with arg arrays
- Command execution uses allowlist for security
See VERSIONING.md for full details.
- Work on
mainbranch (or feature branches merged tomain) - PRs to
maintrigger CI tests - Push
maintoreleasebranch to trigger GitHub Release workflow - Before pushing, follow Regular Development: verify your branch/upstream and working-tree state, preserve unrelated work, and explicitly fetch the intended base for comparison (the tracking branch may differ); integrate it only for conflicts, enforced branch policy, or evidenced integration risk. Run
npm run pregateafter any rebase and before every push. See AGENTS.md's Git Workflow for the full contract.
Pregate proves only the stages it runs; it does not replace required CI or resource-dependent checks. A full-suite plan runs only the always-run guards unless --full is supplied; DB suites, Windows, client build, and boot smoke are reported but not run by pregate.
Nothing to write here — there is no per-branch changelog file or fragment.
/do:release synthesizes the release notes from the commit log when it runs,
so write commit subjects/bodies for a human release-note reader (see Commit
Messages below). See .changelog/README.md for
details.
Note: Some older code or automation notes may still reference a
devbranch workflow. Themain→releaseworkflow described here is the current source of truth.
.gitattributes pins eol=lf for text files across all platforms. To normalize
tracked files in an older Windows clone, first commit or stash unrelated work
(including staged changes). Then run from the repository root:
git add --renormalize .
git diff --cached --stat
git diff --cachedThis reapplies the current attributes to tracked files in the index without
overwriting working files. It also stages any other tracked edits or deletions,
which is why unrelated work must be saved first. Commit only if the reviewed
diff contains the intended normalization changes; an empty diff needs no commit.
Do not use git reset --hard for this repair: it discards uncommitted tracked
changes.
Use conventional commit prefixes with a human-readable subject — a future reader of git log --oneline should understand the change without opening the diff:
feat: add a --dry-run flag to the backup CLI
fix: daily log no longer double-saves on blur
docs: point the API allowlist at commandSecurity.js
PortOS/
├── client/ # React + Vite frontend (Vite dev server on port 5554 under npm run dev)
│ └── src/
│ ├── components/
│ ├── pages/
│ └── services/
├── server/ # Express.js API (port 5555)
│ ├── routes/
│ ├── services/
│ └── lib/
├── data/ # Runtime data (gitignored)
├── docs/ # Documentation
└── .github/workflows # CI/CD
Run these commands from the repository root:
# Run server tests (Vitest, node environment)
npm test --prefix server
# Run client tests (Vitest, happy-dom environment)
npm test --prefix client
# Provision and run the isolated DB-backed suites (portos_test only)
npm run setup:db:test
npm run test:dbSupported full local validation uses the CI worker budget. An unbounded
npm test can oversubscribe a loaded machine: real media, prompt-catalog,
and nested-worker cases then hit their existing budgets. A green focused
file run is evidence for that file only, not a full-suite result.
# Server, then client. The value only lowers each workspace cap (client stays at 2).
PORTOS_PREGATE_MAX_WORKERS=4 npm test
# Focused evidence for one file:
npm test --prefix server -- services/creativeDirector/videoAssembly.test.jsFor release validation, run npm run test:db after the server and client
suites finish rather than alongside them. A concurrent run is supported —
the database restore suite drains a timed-out case before the next one touches
portos_test — but its per-case budgets assume an
unloaded machine, so a concurrent run can time out cases a sequential run
passes.
For server watch mode, run this alternative from the repository root:
npm run test:watch --prefix serverPull requests into main run the tests for affected feature directories, with
conservative fallbacks to Vitest related-test mode or the complete suite. The
pull request into release, nightly CI, and manual CI runs always run the
complete server, client, DB, lint, build, and smoke checks. Pushes to main
run nothing — the pull request gate already covered that tree. Release
publication is blocked until a full CI gate has succeeded on the exact tree
being released. See GITHUB_ACTIONS.md.
See API.md for the complete REST API and WebSocket event reference.
Open a GitHub issue. There's no formal triage SLA — this is a side project run by one person — but clear repro steps or a concrete, scoped proposal are much more likely to get picked up than a vague one.
MIT — see LICENSE.