onesie

module
v0.14.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Nov 7, 2026 License: MIT

README

onesie

Pipe in some text, ask a question, get an answer you can script against. Asks TypeSafe's Jev, directly or through OpenRouter or Cloudflare, Berget's own System One models, Levanto's Sage, or Cloudflare's Clef.

echo 'EVERYTHING IS DOWN, CALL ME NOW' | onesie 'does this convey urgency' -r
# 0.99

Gate an agent's shell commands. The exit code says what to do:

onesie -f shell-safety -q --state 'git status'
# exit 0: run it
onesie -f shell-safety -q --state 'rm -rf ~'
# exit 1: block it
onesie -f shell-safety -q --state 'echo hello > notes.txt'
# exit 7: not sure, ask a person

See Thresholds from evidence for where that gate's numbers come from.

Install

Homebrew, on macOS or Linux:

brew install frodi-karlsson/tap/onesie

The install script checks the download against the release checksums, and its build provenance when gh is logged in:

curl -fsSL https://raw.githubusercontent.com/frodi-karlsson/onesie/main/install.sh | sh

With Go:

go install github.com/frodi-karlsson/onesie/cmd/onesie@latest

Then store a key in a profile with onesie profile create work --provider typesafe, which prompts for it and keeps it in the OS keychain.

In GitHub Actions, setup-onesie installs it with the same checksum and provenance checks, and the key comes from a secret instead of a profile:

- uses: frodi-karlsson/setup-onesie@v1

In Claude Code, the plugin can come first and walk you through the rest:

/plugin marketplace add frodi-karlsson/onesie
/plugin install onesie@onesie

Thresholds from evidence

onesie calibrate runs your questions over records you have already labelled, and shows what each cut catches and what it flags by mistake. Here's the destroys question from shell-safety over 40 labelled commands:

onesie calibrate -f shell-safety -i jsonl --map .command --id .id -m jev-1.13.0 \
    --label destroys=.destroys --label secrets=.secrets --label network=.network \
    --cuts 0.25,0.5,0.65 --out answers.jsonl --resume < commands.jsonl
destroys, yes/no: labelled 40, 16 yes, 24 no, 0 failed. AUC 1.00
flagged means destroys.value >= cut

  cut   flagged  catches           false alarms   right when flagged
  0.25       18  16/16 99% 81-99%  2/24 8% 2-26%  16/18 89% 67-97%
  0.50       15  15/16 94% 72-99%  0/24 1% 1-14%  15/15 99% 80-99%
  0.65        7   7/16 44% 23-67%  0/24 1% 1-14%   7/7  99% 65-99%

worst misses
  echo-overwrite  echo hello > notes.txt  labelled yes  answered 0.37

For destroys, shell-safety blocks at 0.5 and passes below 0.25. Anything in between goes to a person, like the worst miss above.

Commit answers.jsonl, and CI runs the same command with --offline and requirements, which needs no key:

onesie calibrate ... --offline \
    --require 'destroys.catches >= 1' --require 'destroys.false_alarms <= 0 at abstain'

Exit 1 means a requirement no longer holds. Exit 2 means the questions changed, so ask again.

To test a script that uses the gate, ONESIE_MOCK answers every onesie call from a file:

echo '{"destroys": 0.93, "secrets": 0.02, "network": 0.1}' > danger.json
ONESIE_MOCK=danger.json ./gate.sh   # takes the blocked branch

Asking

A yes or no question answers with how likely the yes is. --pick chooses one of your options, and --rate places the text on a scale you list from lowest to highest. -r prints only the answer.

echo 'I was charged twice for my order' | onesie 'who should handle this' --pick billing,shipping,technical -r
# billing
echo 'Third time asking. Fix it or I am leaving.' | onesie 'how frustrated is the customer' --rate calm,annoyed,furious -r
# furious

Give each question a name with --ask, and they all go out in one request:

onesie --ask urgent='is this urgent' \
       --ask team='who should handle this' --pick billing,shipping,technical \
       -o values < ticket.txt
# {"urgent":0.69,"team":"billing"}

--print-questions > .onesie/questions/NAME.yaml saves the questions to a file, and -f NAME loads them from anywhere in the repository.

Recipes

Triage tickets as they come in.

tail -f tickets.jsonl | onesie 'is this urgent' -i jsonl --map .body --id .id -o json

Wire the gate into a script. Exit 0 runs the command, 1 blocks it and 7 asks a person. Any other exit code means there was no answer, as the exit code table says.

onesie -f shell-safety -q --state "$cmd"
case $? in
    0) eval "$cmd" ;;
    1) echo blocked ;;
    7) ask_the_user ;;
    *) echo 'no answer, blocked' ;;
esac

Triage a spreadsheet. The same rows come back with a column per question.

onesie --ask urgent='does `body` convey urgency' -i csv -o csv --merge < tickets.csv > triaged.csv

A spreadsheet export separated by semicolons reads with --delimiter auto, and -o csv writes semicolons back, merged or not.

Run a big batch you can resume. --map sends only the body, --id names each answer, and --resume skips every id the file already answers and asks the rest, failed ones included.

onesie 'is this urgent' -i jsonl -j 8 --map '.body' --id '.id' \
    --out answers.jsonl --resume < tickets.jsonl
jq -c 'select(.answer.value > 0.8)' answers.jsonl

Comment on a pull request. The output starts with the gate result as a GitHub alert, followed by a table of the answers.

onesie 'does this explain why the change is needed' --assert 'answer.value > 0.6' \
    -o markdown --state "$PR_BODY" | gh pr comment "$PR" --body-file -

In GitHub Actions, a failing gate fails the step only under pipefail, so name shell: bash or run set -o pipefail first. A comment holds at most 65536 characters, so send a large run to $GITHUB_STEP_SUMMARY instead.

Rank records by several questions. One --ask per dimension scores every record, and jq weighs the answers and sorts by the sum. .value is the yes or no probability, and .norm is the rate's position between 0 and 1. The weighting lives in jq, since --assert has no arithmetic, and select(has("error") | not) drops the records that failed.

onesie --ask impact='does this help many users' \
    --ask effort='how much work is this' --rate trivial,small,medium,large \
    -i jsonl --map '.body' --id '.id' -o json < ideas.jsonl |
    jq -s 'map(select(has("error") | not)) | map({id, score: (0.7 * .impact.value + 0.3 * (1 - .effort.norm))}) | sort_by(-.score)'

Run against a local server. onesie talks to any server that speaks a provider's API, such as ollaya, which serves TypeSafe's System One API on this machine. Point ONESIE_BASE_URL at it and name a model it serves:

ONESIE_BASE_URL=http://localhost:11435 onesie -m winnow:e4b 'is this urgent' < ticket.txt

A base URL other than the provider's own needs no key, and a run with none sends no Authorization header. --allow-http is needed only for plain http to a host other than this machine. A server that speaks another provider's API takes that --provider. onesie profile show names where the base URL came from, so a variable left exported is easy to spot. A profile holds the same setup, made with onesie profile create local --provider typesafe --base-url http://localhost:11435 --model winnow:e4b and the key prompt left empty.

Starter gates. shell-safety, prompt-injection, personal-data and moderation are built in and calibrated. onesie questions lists them, and examples/README.md has their tables.

Also

  • Profiles and providers. A profile names a provider, TypeSafe, OpenRouter, Berget, Levanto or Cloudflare, and holds its key, as in onesie profile create work --provider openrouter. Two profiles can hold two keys for one provider, and --profile NAME picks one for a run. A run with no choice uses the default profile, or TypeSafe on TYPESAFE_API_KEY when there are no profiles. --provider NAME runs without a profile, on the provider's key variable, which suits CI. Cloudflare needs an account id beside its token.
  • Caching. --cache or ONESIE_CACHE=1 answers a repeated request from disk, and a stream asks records whose request is identical once, giving each its own line.
  • Dry runs. --print-request writes the exact request bodies without sending them, to inspect or to replay later with -i request, and needs no key. --mock rehearses a whole command, gates and exit codes included, from a file of answers.
  • Images. --image photo=door.jpg puts a PNG or JPEG in the state, and --box asks where something is in it. Both are experimental on TypeSafe's side.

Why no MCP server

onesie ships agent skills instead of an MCP server:

  • Validation. The CLI already checks every question, flag and assertion before any request, and an agent reads the same messages and exit codes a person does.
  • Documentation. onesie --help, -V and the error messages come from the binary, so they stay in step with it.
  • Discoverability. Skills have room for more prose than a tool description, such as worked recipes and the mistakes to avoid, and CI checks their examples against the binary.

Reference

REFERENCE.md covers asking, gating, testing a gate, calibrating, streams and resume, caching, profiles and providers, exit codes and the rest of the flags.

Contributing

See CONTRIBUTING.md.

License

MIT. See LICENSE.

Directories

Path Synopsis
cmd
examplesanswers command
Command examplesanswers regenerates the starter sets' committed answers files from the live API, with the pinned model.
Command examplesanswers regenerates the starter sets' committed answers files from the live API, with the pinned model.
examplesimage command
Command examplesimage writes the example image the docs and skills use.
Command examplesimage writes the example image the docs and skills use.
formulagen command
Command formulagen writes the Homebrew formula for a release from the release's checksums.txt.
Command formulagen writes the Homebrew formula for a release from the release's checksums.txt.
onesie command
Command onesie asks System One models typed questions about text from the shell.
Command onesie asks System One models typed questions about text from the shell.
proseblocks command
Command proseblocks reads a unified diff on stdin and writes the prose blocks of the Go and Markdown files that overlap an added line as JSON lines of {"id":"path:line","text":"..."}.
Command proseblocks reads a unified diff on stdin and writes the prose blocks of the Go and Markdown files that overlap an added line as JSON lines of {"id":"path:line","text":"..."}.
releaseprep command
Command releaseprep checks a release tag against the existing ones and bumps the plugin manifests to it.
Command releaseprep checks a release tag against the existing ones and bumps the plugin manifests to it.
settingsgen command
Command settingsgen writes the question file schema and the REFERENCE.md settings blocks from the settings rows.
Command settingsgen writes the question file schema and the REFERENCE.md settings blocks from the settings rows.
skillcheck command
Command skillcheck dry runs every rule's bad and good example under skills/, checks the flags and commands the prose names against onesie --help, and checks the punctuation of the docs.
Command skillcheck dry runs every rule's bad and good example under skills/, checks the flags and commands the prose names against onesie --help, and checks the punctuation of the docs.
skilleval command
Command skilleval dry runs every onesie command an agent wrote during the last claude plugin eval run.
Command skilleval dry runs every onesie command an agent wrote during the last claude plugin eval run.
skillgen command
Command skillgen generates the per client skill files from skills/.
Command skillgen generates the per client skill files from skills/.
Package examples describes the starter question sets, so the tests and the tool that regenerates their answers read each set the same way.
Package examples describes the starter question sets, so the tests and the tool that regenerates their answers read each set the same way.
questions
Package questions holds the starter question sets built into onesie, so -f finds them by name with no copy step.
Package questions holds the starter question sets built into onesie, so -f finds them by name with no copy step.
internal
answer
Package answer normalizes API answers into the shape the CLI prints and applies the per question policy.
Package answer normalizes API answers into the shape the CLI prints and applies the per question policy.
answersfile
Package answersfile opens, locks, resumes and compacts the file a run writes its answers to.
Package answersfile opens, locks, resumes and compacts the file a run writes its answers to.
argv
Package argv records group local flags in the order pflag encounters them, so the question groups in a command line can be reconstructed after parsing.
Package argv records group local flags in the order pflag encounters them, so the question groups in a command line can be reconstructed after parsing.
assert
Package assert evaluates a boolean expression over a normalized record.
Package assert evaluates a boolean expression over a normalized record.
cache
Package cache stores API responses on disk under a sha256 key, with private modes, atomic writes, a lifetime for model aliases and a size cap enforced by least recently used eviction.
Package cache stores API responses on disk under a sha256 key, with private modes, atomic writes, a lifetime for model aliases and a size cap enforced by least recently used eviction.
calibrate
Package calibrate reads the labels a calibration run compares answers with, and scores and reports how well the answers agree with them.
Package calibrate reads the labels a calibration run compares answers with, and scores and reports how well the answers agree with them.
cli
Package cli assembles the onesie command tree.
Package cli assembles the onesie command tree.
creds
Package creds resolves, reads and writes the profiles file that holds each profile's API key, and converts the credentials.json it replaces.
Package creds resolves, reads and writes the profiles file that holds each profile's API key, and converts the credentials.json it replaces.
delimiter
Package delimiter parses delimited input separators.
Package delimiter parses delimited input separators.
engine
Package engine runs one evaluation per record the source yields, bounded by concurrency and ordered by input position.
Package engine runs one evaluation per record the source yields, bounded by concurrency and ordered by input position.
formula
Package formula renders the Homebrew formula for a onesie release from the release's checksums.
Package formula renders the Homebrew formula for a onesie release from the release's checksums.
input
Package input resolves where a state comes from and reads it, so the detection rule lives in one place rather than being rediscovered at every call site.
Package input resolves where a state comes from and reads it, so the detection rule lives in one place rather than being rediscovered at every call site.
interrupt
Package interrupt lets a caller stop waiting on a read that has no deadline.
Package interrupt lets a caller stop waiting on a read that has no deadline.
jq
Package jq compiles and runs the jq expressions that --map and --id take, through gojq.
Package jq compiles and runs the jq expressions that --map and --id take, through gojq.
jsonschema
Package jsonschema holds the JSON Schema nodes onesie builds its schemas from, with properties kept in the order they are declared.
Package jsonschema holds the JSON Schema nodes onesie builds its schemas from, with properties kept in the order they are declared.
limits
Package limits holds the constants --version reports.
Package limits holds the constants --version reports.
mock
Package mock reads a file of canned answers and checks it against the questions a run asks, so the run can answer from it with no key and no network.
Package mock reads a file of canned answers and checks it against the questions a run asks, so the run can answer from it with no key and no network.
num
Package num writes and rounds the numbers onesie prints, so every output mode shows the same one.
Package num writes and rounds the numbers onesie prints, so every output mode shows the same one.
output
Package output encodes a normalized record in each of the modes the CLI offers.
Package output encodes a normalized record in each of the modes the CLI offers.
patherr
Package patherr strips the operation and path an *fs.PathError carries, for a message that names the path itself.
Package patherr strips the operation and path an *fs.PathError carries, for a message that names the path itself.
plan
Package plan turns a recorded command line into a validated invocation, ready to run.
Package plan turns a recorded command line into a validated invocation, ready to run.
proseblocks
Package proseblocks finds the pieces of prose a change touches in Go and Markdown files: one block per comment group, paragraph or list item.
Package proseblocks finds the pieces of prose a change touches in Go and Markdown files: one block per comment group, paragraph or list item.
providers
Package providers words onesie-go's provider list for help and messages, so a provider the library adds reaches every one of them.
Package providers words onesie-go's provider list for help and messages, so a provider the library adds reaches every one of them.
qfile
Package qfile loads a question file or a raw API request body into the ordered question slice the planner already consumes.
Package qfile loads a question file or a raw API request body into the ordered question slice the planner already consumes.
release
Package release checks a release tag against the existing ones and bumps the plugin manifests to it.
Package release checks a release tag against the existing ones and bumps the plugin manifests to it.
settingrow
Package settingrow holds every run setting as one row: its flag, its environment variables, its question file key, its profile members, its kind and its help.
Package settingrow holds every run setting as one row: its flag, its environment variables, its question file key, its profile members, its kind and its help.
settings
Package settings merges sources and validates the settings of a run.
Package settings merges sources and validates the settings of a run.
settingsgen
Package settingsgen writes the files the settings rows generate: the question file schema and the settings blocks of REFERENCE.md.
Package settingsgen writes the files the settings rows generate: the question file schema and the settings blocks of REFERENCE.md.
skillcheck
Package skillcheck dry runs every rule's bad and good example in a skill.
Package skillcheck dry runs every rule's bad and good example in a skill.
skilleval
Package skilleval dry runs every onesie command an agent wrote during a claude plugin eval run, since the eval has no grader that can run code.
Package skilleval dry runs every onesie command an agent wrote during a claude plugin eval run, since the eval has no grader that can run code.
skillgen
Package skillgen decodes and validates skill.json, the schema a generated skill is built from.
Package skillgen decodes and validates skill.json, the schema a generated skill is built from.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL