mirror of
https://github.com/profullstack/logicsrc.git
synced 2026-10-05 14:15:33 +00:00
* OpenErrand 0.1: an errand on a website with no API, with the human steps kept human docs/openerrand.md mints OpenErrand: one JSON file per errand (register an account, download a transcript) naming the site, the inputs with a sensitivity class and ordered sources (document, vault, prompt, generate, derive, candidate, literal), field rules matched by id then label, page and wait steps, five human gates a runner never performs (declare, identity-proofing, code, mail, captcha), outcomes, the never-retried shared secret, vault and download outputs, hand-off cards that may name only public inputs, the publisher index at /.well-known/openerrand.json, and thirteen runner rules. The worked example is the MyFTB business registration that cli-tools `ftb` performs (profullstack/cli-tools#125), with no personal data. - @logicsrc/schemas: openerrand + openerrand-index schemas and fixtures - @logicsrc/validators: semantic checks (references, templates, no personal or secret input on a card) and tests that validate the spec's own examples - logicsrc-web: registry entry (process family), /openerrand landing page, the example and the index served as static files, contract tests Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * OpenErrand: hand-off cards stay on the surface that owns the data Anthony's ruling: tax and finance data never touches a social or promotion tool, and nothing is sent to a CPA or preparer. - Hand-off cards are delivered only on the surface that owns the errand's data (for a tax or finance errand, the principal's finance app through its CLI, PWA, MCP server or API, such as CoinPay, or the runner's terminal), never a social, promotion or third-party posting service, and never to anyone but the principal. A card for an errand with personal or secret inputs does not leave that surface. Runner rule 9 says the same. - The run record and the sample run name the card by an opaque id (pin-letter/7f3k2q) instead of a mynaposter.com URL; the myna mention is gone. - `principal: represented` no longer cites a preparer with a power of attorney. - The FTB card's last step no longer suggests sending the PIN to someone else. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * OpenErrand: user-agent rule, captcha solver policy, reference runner note Anthony's answers on #227 ("go with your recommendations"): - Rule 11: a runner may run headless with a normal desktop browser user agent (dropping HeadlessChrome) and nothing more: no fingerprint spoofing beyond the UA string, no stealth plugins, no solving or evading a bot challenge. A challenge the browser completes itself is a wait step; any other is a captcha gate. - Captcha solvers: new site.sector and captcha step `solver` (forbidden by default | allowed). Never allowed on government, tax, financial, healthcare or identity-provider sites, nor on any errand with a declare or identity-proofing step or a secret input; elsewhere only when the file says so, with every use logged. The validator rejects `allowed` in the forbidden set or without a stated sector; six new tests. The FTB example states sector "tax". - Reference runner: @logicsrc/openerrand / `logicsrc errand run`, marked in progress; ftb stays the runner the example was taken from. - Name stays OpenErrand; family stays Agents and process. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * OpenErrand reference runner: @logicsrc/openerrand and logicsrc errand Ship the runner docs/openerrand.md promised. `logicsrc errand run <file>` reads an OpenErrand 0.1 file, validates it with @logicsrc/validators, and drives headless Chrome through it under the spec's thirteen rules; `errand validate` shows what a file will ask of you and `errand status` shows the last run of each errand, its card and any lockout. The engine is generalised from cli-tools `ftb` (PR #125) with no dependency on cli-tools: the CDP client and Chrome finder from wcag.ts, the page reader, native-setter fill and forward-button picker from ftb-run.ts, and the rule matcher, throttle and outcome logic from ftb.ts, all now driven by the file. - Inputs: document (an extractor hook; the one shipped runs a local command that reads JSON requests and prints records), vault (teams or OpenCreds), prompt (no echo for secrets), generate, derive, candidate, literal. `--input name=value` wins. Shared-secret candidates are ranked as the spec says, one is submitted, and a rejection lists the others for --candidate. - Rules: id before label, step rules first, choices before text, an id match final, an unmatched required field stops the run naming it. - Gates: declare only with --declare after the values are shown; identity proofing never touched (URL only) and handed over or stopped on; code from the terminal or a code file, used once, a wrong code waits for the next; mail ends the run waiting with the card; captcha is the person's, and a CaptchaSolver interface is called only where the spec permits (no solver is bundled); wait steps are polled, never solved. - Throttle: 2 runs per errand and account in 30 minutes, 4 a day, 2 minutes between runs on a site, lockouts from metadata.lockout or a default, held per site and account, never lifted by --force. - Outputs: credentials written before success to a teams vault by pull, merge, push (metadata.vault or --vault), else a 0600 file said aloud; downloads type-checked and never overwritten with different bytes; cards only in the local run record. - The user agent is Chrome's own with HeadlessChrome replaced, given at launch: a CDP override did not reach a navigation the page's own script started, which is exactly the proof-of-work interstitial case. Tests: 85 in the package (rule engine, inputs, gates, throttle, outcomes, captcha gating, vaults, outputs, commands) including an integration test that runs the published FTB example unchanged in real headless Chrome against a local HTTPS fake site (Chrome maps webapp.ftb.ca.gov to it and every other host to NOTFOUND; all data fictional), and 2 in the CLI. CLI 0.6.0 -> 0.7.0; @logicsrc/schemas and @logicsrc/validators 0.3.0 -> 0.4.0 (the OpenErrand schemas, and the vocabularies now exported for runners); PRD 0009; the spec's Reference runner section and the landing page say it ships. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
117 lines
6.6 KiB
Markdown
117 lines
6.6 KiB
Markdown
# @logicsrc/openerrand
|
|
|
|
The reference runner for [OpenErrand](https://logicsrc.com/docs/openerrand):
|
|
one JSON file that describes an errand on a website with no API, run in
|
|
headless Chrome, stopping at every step that belongs to a person.
|
|
|
|
It reads an errand file, validates it with `@logicsrc/validators`, resolves
|
|
every input before the browser opens, then for each page finds its step,
|
|
tests the outcomes, fills the form from the rules (id first, label second,
|
|
choices before text), hands every gate to a person, and presses the forward
|
|
button, until the site answers or the runner has to stop.
|
|
|
|
## Install
|
|
|
|
```bash
|
|
curl -fsSL https://logicsrc.com/install.sh | sh
|
|
logicsrc errand --help
|
|
```
|
|
|
|
The commands live in this package and the umbrella CLI mounts them as
|
|
`logicsrc errand`. To embed the runner:
|
|
|
|
```bash
|
|
npm install @logicsrc/openerrand
|
|
```
|
|
|
|
## Commands
|
|
|
|
```bash
|
|
logicsrc errand validate ftb-register-business.json
|
|
logicsrc errand run ftb-register-business.json --extractor "python3 extract.py ~/taxes" --dry-run
|
|
logicsrc errand run ftb-register-business.json --extractor "python3 extract.py ~/taxes" --declare
|
|
logicsrc errand status
|
|
```
|
|
|
|
| Flag | What |
|
|
| --- | --- |
|
|
| `--input name=value` | Give an input's value (repeatable). Wins over every source. |
|
|
| `--dry-run` | Fill every page up to the first that holds a declaration or a shared secret, show it with secrets masked and the declaration word for word, and stop before its forward button. Not counted by the throttle. |
|
|
| `--declare` | Your consent, for this run, to tick the declarations the errand names. Never read from a file, the environment or a saved default. |
|
|
| `--headful` | A visible window, so you can take identity proofing or a captcha yourself. |
|
|
| `--chrome PATH` | The Chrome or Chromium binary (default: `CHROME_PATH`, then PATH, then the Puppeteer and Playwright caches). |
|
|
| `--vault TARGET` | `teams:<team>/<project>/<env>`, `opencreds[:<field>]` or `file:<path>`. Default: the file's `metadata.vault`, else a 0600 file. |
|
|
| `--extractor CMD` | The local command that reads your documents (see below). |
|
|
| `--candidate N` | Which shared-secret candidate to submit; a rejection lists the others. |
|
|
| `--account NAME` | Which account at the site, for the throttle. |
|
|
| `--force` | Lift the per-window, per-day and spacing caps. Never a lockout. |
|
|
| `--yes` | Run a file whose SHA-256 changed since its last run without asking. |
|
|
| `--json` | Print the run record on stdout. |
|
|
|
|
Exit codes: 0 success, waiting or dry run; 1 rejected; 2 invalid file or
|
|
usage; 3 stopped (a gate, an unmatched field, a loop, off-site, a timeout);
|
|
4 refused by the throttle.
|
|
|
|
## Inputs
|
|
|
|
| Source | Served by |
|
|
| --- | --- |
|
|
| `document` | `--extractor`: a command on this machine. It gets `{ "errand", "documents": [{ "input", "form", "field", "match" }] }` on stdin and prints `[{ "form", "field", "value", "year", "label", "file", "page" }]`. The runner applies `match`, `years`, `pick` and `transform`, and keeps the values in memory only. No extractor is bundled. |
|
|
| `vault` | The vault target, read-only here. |
|
|
| `prompt` | The terminal; a secret does not echo. With no terminal the next source is tried. |
|
|
| `generate` | `crypto.randomInt`, at least one character of each class, a letter first when letters are allowed. |
|
|
| `derive`, `candidate`, `literal` | The file and the other inputs. |
|
|
|
|
A shared-secret input's document sources become a ranked list of candidates
|
|
(sources in order, newest year first within each). A run submits one; a
|
|
rejection ends the run and lists the others for you to choose with
|
|
`--candidate`. Nothing is ever retried on its own.
|
|
|
|
## Gates
|
|
|
|
| Gate | What the runner does |
|
|
| --- | --- |
|
|
| `declare` | Stops on the page and prints the statement word for word, unless you passed `--declare`; then it shows the values on the page (secrets masked) and ticks the box. |
|
|
| `identity-proofing` | Never touches the provider's pages (it reads only the URL). Headless, it stops and tells you; with `--headful` at a terminal it waits until the page is back on the site. |
|
|
| `code` | The terminal prompt, or the code file `~/.local/share/logicsrc/errand/codes/<name>.code` written by whoever holds the phone. Used once, never logged. A wrong code waits for the next one. |
|
|
| `mail` | Ends the run waiting, with the deadline and the hand-off card in the run record. |
|
|
| `captcha` | Yours: a visible window with `--headful`, or the run stops. A program may pass a `CaptchaSolver`, and it is called only when the step says `solver: allowed` and the errand is outside the forbidden set (a stated sector that is not government, tax, financial, healthcare or identity-provider; no declaration or identity proofing; no secret input). Each use is logged with the time, URL and service. No solver ships with this package. |
|
|
| `wait` | Polled until its match no longer fits, then the run goes on. Never solved or bypassed. |
|
|
|
|
## What it keeps
|
|
|
|
Under `$LOGICSRC_ERRAND_HOME`, else `~/.local/share/logicsrc/errand` (files
|
|
0600, directories 0700):
|
|
|
|
| Path | What |
|
|
| --- | --- |
|
|
| `throttle.json` | Attempts and lockouts. 2 runs of an errand per account in 30 minutes, 4 a day; 2 minutes between runs on one site; nothing during a lockout. A lockout is the file's `metadata.lockout.text` pattern (lasting `metadata.lockout.duration`) or a default pattern (35 minutes), and it holds every errand on that site and account. |
|
|
| `approvals.json` | The SHA-256 of each errand file last run. A changed file is shown and not run without `--yes` or a yes at the terminal. |
|
|
| `runs/` | One run record per run: outcome, page, candidate (no value), card, deadline. Never an input value. |
|
|
| `pages/<name>.jsonl` | The page log: each page's fields (selector, type, label, required, options) and a result page's text. Never a value. |
|
|
| `profiles/<host>/` | One Chrome profile per site, kept so a passed bot check stays passed. |
|
|
| `codes/<name>.code` | Where a code may be written. |
|
|
| `credentials/<name>.env` | Credentials when no writable vault is named. |
|
|
|
|
Hand-off cards stay in the run record and `errand status`. They are never
|
|
posted anywhere, and a card that names a personal or secret input is refused.
|
|
|
|
## Browser
|
|
|
|
Chrome over the DevTools protocol, no dependency. The user agent is Chrome's
|
|
own with `HeadlessChrome` replaced by `Chrome`, given at launch so it reaches
|
|
every request; nothing else about the browser is changed.
|
|
|
|
## Library
|
|
|
|
```ts
|
|
import { loadErrand, resolveInputs, runErrand, openCdpDriver, Store, fileVault } from "@logicsrc/openerrand";
|
|
```
|
|
|
|
`runErrand` takes a `Driver` factory, so an embedder can bring its own
|
|
browser; the tests drive it with a scripted fake and one integration test runs
|
|
the FTB example in real headless Chrome against a local fake site.
|
|
|
|
## License
|
|
|
|
MIT
|