Read-only tooling for Previred — Chile's platform for imposiciones laborales
(cotizaciones previsionales). A TypeScript core behind a CLI, built as the
companion to the separate sii (taxes) project.
Status: auth is verified live end-to-end (the authenticated marker is pinned),
indicadoresis verified live, andpagosis built and fully tested against a synthetic fixture — its live round-trip is not yet verified. See docs/CURRENT_STATUS.md and docs/ONBOARDING.md.
Stack: TypeScript (strict, NodeNext) · Node ≥ 20 · pnpm workspaces · Playwright/Chromium (optional peer, headed login only) · commander · vitest. Details in docs/STACK.md.
pnpm install
pnpm build
npx playwright install chromiumRun the test suite — no browser and no network needed; every seam has an in-memory fake:
pnpm testprevired auth loginOpens Chromium at Previred's real login page. You type your RUT and password into Previred's own form — the password never crosses this program's boundary, is never read, stored, logged, or written to disk. Only cookies are persisted.
previred auth status # local read (JSON by default)
previred auth status --refresh # ask Previred whether the session is still live
previred auth logout # wipe the local sessionprevired indicadores # public indicadores previsionales — no login needed
previred pagos --periodo YYYYMM # planillas pagadas for a period (needs a session)
previred observe --timeout 600 # map the portal read-only; never logs inAdd --human to any command for readable text instead of JSON.
There is nothing to configure and no credentials are ever stored. This tool
takes no environment variables, no config file, and no .env — by design
(ADR-005). The only thing you supply is typed by you, interactively, into
Previred's own page:
| Value | Where it goes | Stored? |
|---|---|---|
| Previred RUT | Typed by you into Previred's login form in the headed browser | Only as part of local session metadata |
| Previred clave | Typed by you into Previred's login form in the headed browser | Never — not read, logged, or persisted |
The password never crosses this program's boundary. What does persist, locally
only, under ~/.previred/ (mode 0600 on POSIX, ACL-hardened on Windows,
ADR-007):
| File | Contents |
|---|---|
~/.previred/session.json |
Session cookies only — no secrets, no forms |
~/.previred/audit.jsonl |
Append-only local audit receipt |
previred auth logout wipes both. Neither lives inside the repository, and the
.gitignore refuses .previred/, .env* and raw portal captures as a
belt-and-braces measure.
Previred returns HTTP 200 at an unchanged URL whether or not you are logged in, so this tool identifies a logged-in page by its content, and refuses to guess:
previred auth login --captureLog in normally; a redacted, structural snapshot of every page seen is
written to docs/previred-contract/auth-login.observed.json — element ids, form
shapes, cookie names, and candidate marker strings, with no field values, no
cookie values, and RUTs / emails / long digit runs stripped. Pick a marker from
it and pin it in packages/core/src/auth/markers.ts.
- Read-only by construction. An allowlist of dispatchable programs is enforced at runtime by a session decorator and pinned by test. The core physically cannot reach Previred's declaración or pago programs (ADR-004).
- No secrets on disk. Cookies only, mode
0600on POSIX and ACL-hardened on Windows (ADR-005, ADR-007). - Fails closed. An unrecognised page is never treated as authenticated (ADR-003).
- Never retries after a refusal — Previred's lockout policy is unknown and this account pays real cotizaciones.
| Code | Meaning |
|---|---|
| 0 | OK |
| 1 | Unclassified error |
| 2 | Not authenticated / session expired |
| 3 | Login not completed |
| 4 | Rate limited |
| 5 | Read-only guard refused the request (a bug in the caller) |
| 6 | Previred's page shape changed (needs a human to re-observe) |
61 TypeScript files, ~11k lines, 206 tests, 12 ADRs - a small codebase built around one hard guarantee: it cannot spend your money.
| Languages | TypeScript (strict, NodeNext), Node >= 20 |
| Architecture | pnpm monorepo (core library + CLI), ports-and-adapters with injectable seams |
| The central idea | A fail-closed read-only rail: three gates (navigation URL, form body, and in-page evaluate) refuse any program not on a test-pinned allowlist. Payment programs are undispatchable by construction, and tests prove it without a browser. |
| Credential posture | The program never sees your password - you type it into Previred's own page in a headed window; only session cookies persist, ACL-hardened on disk. |
| Auth detection | The portal returns HTTP 200 whether or not you are logged in, so authentication is detected from page content and fails closed on anything unrecognised. |
| Testing | Vitest, 206 tests, zero network. Fake portal sessions script whole multi-hop navigation chains. |
| Tooling | ESLint, Prettier, 12 ADRs, MIT |
Skills demonstrated: security-first API design, allowlist/deny-by-default modelling, Playwright browser automation, HTML parsing, test-pinned invariants, and honest documentation of limits.
- Unofficial project. Not affiliated with, sponsored by, or endorsed by Previred or any Chilean pension institution. The name is used only to describe what this interoperates with.
- Automates a third-party portal. It works against an observed interface, not a stable public API: Previred can change the site without notice, and may restrict or block automated access (ADR-009). Use it only with an empresa you own or are authorised to act for.
- Read-only by construction — not by promise. The rail refuses payment and declaration programs, and that refusal is pinned by tests. It is still your responsibility to confirm what any command does before running it against a real account.
- Not professional advice. Output is informational. Verify against the official portal before relying on it for payroll, contributions, or any filing. Deadlines, amounts, and penalties remain the user's responsibility.
- Credentials. You type your RUT and clave into Previred's own page in a visible browser window; this project never stores them. Only session cookies persist locally.
- No warranty. Provided "as is", without warranty of any kind (see LICENSE).
MIT.