A portable secrets vault, exploring fresh approval for each governed open.
Quick start · Witnessed walkthrough · Self-hosting · Recovery · Release status · Security
Warning
Jury is a pre-alpha implementation. It does not yet protect secrets and must not be used with real credentials. It has not received independent whole-product professional security review.
Jury is an experimental implementation of a portable encrypted vault where
opening a governed item can require fresh approval from a jury. The project
remains on 0.x releases; the portable artifact and witness protocol both
start at version 1. The defining release path requires signed approval and
witness contributions for the exact item revision and action before an
endpoint can open it. Direct slots remain an explicit unilateral mode and
carry no quorum claim.
The design separates carrying a vault from authority to open it. An encrypted artifact can travel with a Git repository, while private identities and local state stay outside Git. For governed access, approval is tied to an exact item revision and action: reading a field, rendering a template, or passing a value to a child process.
| Concept | Role in the design |
|---|---|
| Portable vault | Encrypted items and access policy in a versioned artifact |
| Principal | A human or machine identity with item-scoped grants |
| Approval | A signed decision about the exact requested action |
| Witness | A service that contributes to an authorized governed open |
| Receipt | Signed decision evidence with explicit limits on what it proves |
Witnessed access is the defining goal of the first experimental release. Direct access is an explicit unilateral mode: a direct recipient can open its authorized item alone. An item with a direct slot has no quorum claim as a whole. Neither mode prevents an authorized endpoint or child from retaining plaintext.
Version 0.0.1 is experimental. Check GitHub releases for publication status and versioned downloads. The 2026-09-08 Linux CLI audit passed ten packaged CLI journeys on Debian 12 (glibc 2.36), including witnessed access and recovery. Its four follow-up findings are addressed: rollover and suite migration are explicitly included in 0.0.1, the repaired fuzz lockfile passes the bounded suite, and recovery/TLS diagnostics explain the required filesystem layout and permissions. Passing the exercised paths does not establish security for real secrets. Private vulnerability reporting is available through the security policy, and the maintainer has confirmed security-alert email delivery is enabled. Publication still requires a verified release signature and a freshly verified candidate bound to the final source and documentation.
To build and install both commands from source:
git clone https://github.com/bpcakes/jury.git
cd jury
cargo build --locked --release -p jury -p jury-witness
install -Dm755 target/release/jury "$HOME/.local/bin/jury"
install -Dm755 target/release/juryd "$HOME/.local/bin/juryd"
export PATH="$HOME/.local/bin:$PATH"
jury --version
juryd --helpUse Linux x86_64 with Git, a native C/C++ build toolchain, and Rust/Cargo. The
workspace declares Rust 1.90 as its minimum; the release recipe was tested with
Rust 1.97.0. Both binaries report 0.0.1. macOS, Windows, ARM release packages,
and the terminal UI are outside the tested release scope. For reproducible
packaging and later binary installation, see
Linux release preparation.
Use a disposable shell and synthetic values only. This creates a new Git repository and keeps its test identities, local state, and output in separate directories under one private temporary root:
umask 077
EXAMPLE_ROOT="$(mktemp -d /tmp/ExampleJury.XXXXXX)"
mkdir -m 700 "$EXAMPLE_ROOT/repository" "$EXAMPLE_ROOT/identities" \
"$EXAMPLE_ROOT/state" "$EXAMPLE_ROOT/output"
export JURY_IDENTITY_HOME="$EXAMPLE_ROOT/identities"
export JURY_STATE_HOME="$EXAMPLE_ROOT/state"
git init --quiet "$EXAMPLE_ROOT/repository"
cd "$EXAMPLE_ROOT/repository"
jury identity init
jury vault init
jury item create ExampleItem --allow-direct
jury field set ExampleItem ExampleField
jury item list
jury field list ExampleItem
jury read --direct ExampleItem ExampleField --out "$EXAMPLE_ROOT/output/value.txt"
jury vault audit verifyChoose and confirm a test identity passphrase. At the field prompt, type
ExampleSecret and press Ctrl-D; Enter would become part of the value.
The read creates a mode-0600 file without printing the value. Its destination
must be absent; use --overwrite only when replacing that selected output is
intentional. The encrypted shared artifact is repository/.jury/vault.json;
identities and local state are outside that repository. Retain the whole test
root while using the vault. Exit the disposable shell when finished so its
path overrides do not affect other vaults.
Direct access is unilateral. For approval-governed access, follow the witness operator walkthrough from actor registration through two-terminal approval and receipt verification. Configure all needed operations before making the item witnessed-only. That conversion removes its direct slots; the direct examples above no longer apply to it. The operator guide states the current policy replacement and recovery limits.
| Next task | Guide |
|---|---|
| Configure and operate witnesses and anchors | Self-hosting |
| Add items after governing existing descriptors | Item creation |
| Grant or revoke a vault owner | Owner changes |
| Back up, restore, or rehearse recovery | Recovery |
| Use dotted names or arbitrary public review labels | Reference syntax |
| Understand boundaries or planned work | Architecture, master plan |
| Develop and verify a change | Contributing |
The native Linux CLI currently handles:
- portable identity and vault setup;
- direct item, field, principal, and access operations with explicit unilateral status;
- witnessed-policy configuration and owner-signed review labels;
- governed witnessed read, template injection, transparent exec, and brokered run;
- foreground governed access, detached request previews, complete inspection, offline status, interactive approval/denial, and cancellation;
- privacy cover and local audit verification;
- direct transparent execution and bounded brokered execution behind
--direct; - signed portable-ciphertext export, inspection, and strict import;
- public witness-policy export and per-witness checkpoint propagation status;
- bounded offline inspection and verification of witnessed-decision receipts;
- owner backup creation, full verification, absent-target restore, and real recovery drills;
- public history and capacity status.
For piped field input, --passphrase-stdin consumes the identity passphrase
line first and stores only the remaining bytes as the field value. It overrides
all inherited passphrase environment variables, including backup and new-identity
variables: supply every requested passphrase and confirmation in prompt order.
With a terminal attached it still selects stdin and waits for hidden input,
even if an environment variable was previously sufficient. Unattended jobs
should use a pipe with the full input sequence or omit the flag and configure
every required environment source; do not allocate a terminal expecting the
flag to use environment values.
Without that flag, a configured JURY_IDENTITY_PASSPHRASE consumes no stdin;
provide only the intended field bytes. Do not mix these input layouts.
JURY_IDENTITY_PASSPHRASE authenticates the existing identity for vault init,
audit verification, identity public/prove, and other authenticated commands.
JURY_NEW_PASSPHRASE supplies the new passphrase for identity init, passphrase
changes, and restored identities. Without those sources, the CLI prompts and
confirms new passphrases. Keep passphrases out of command arguments and shell history.
At a terminal, jury field set ITEM FIELD reads hidden input, with or
without --value-stdin. Ctrl-D finishes immediately without adding a newline;
Enter adds a newline to the stored value. Backspace erases one byte on the
current line; Ctrl-U clears that line. Ctrl-C cancels without saving and restores
terminal settings. For exact binary bytes, pipe input with --value-stdin.
Initialize the selected human identity with jury identity init, then create
its vault with jury vault init. When retrying setup, retain the same
--identity or --identity-file selection, home flags, and environment
overrides. Identity creation and vault creation are separate operations.
| Task | Command |
|---|---|
| Inspect the selected vault | jury vault status |
| Discover directly accessible items | jury item list |
| Create an item with direct access | jury item create ITEM --allow-direct |
| List fields | jury field list [ITEM] |
| Write or remove a field | jury field set ITEM FIELD, jury field remove ITEM FIELD |
| Inspect grants or policy | jury access list ITEM, jury policy status ITEM |
| Configure witnessed authority | jury policy require witnessed ITEM … |
| Explicitly allow direct authority | jury policy allow direct ITEM … |
| Reseal unchanged item state | jury privacy cover ITEM |
| Read, render, or launch a child | jury read, jury inject, jury exec, jury run |
| Export witness configuration | jury witness policy-material --out FILE, jury witness checkpoint --out FILE |
jury item list reports the same directly accessible catalog as
jury access list --me. Item and field listings omit inaccessible and
witnessed-only items; an empty listing does not mean the vault is empty.
For governed access, start read, inject, exec, or run with its witnessed
options and keep it running while another terminal approves the file published
at --request-out. jury request preview creates an inspection artifact only;
it cannot be executed later. Use request inspect or request status to inspect
an artifact, and request cancel to submit cancellation for a foreground request.
See the witness walkthrough for the full
approval and cancellation commands.
Existing scripts remain supported: jury init is a shortcut for
jury vault init; jury vault field and jury vault read retain their behavior. Policy
and privacy commands still accept --item ITEM instead of positional ITEM
(but reject both together). Witness exports still accept --output for
--out. request create remains an alias for request preview, and the
legacy request execute command still starts a fresh governed read. Its
--item/--field flags correspond to the positional item/field labels of
jury read; it never resumes an existing request. Existing JSON operation
labels remain stable, including request-create for a preview and
access-list-me for the older access listing; jury item list reports
item-list.
In the direct example above, create templates using exact ITEM/FIELD
references. Run these commands from the example repository while its identity
and state overrides are still set:
printf 'value={{ExampleItem/ExampleField}}\n' > "$EXAMPLE_ROOT/output/template.txt"
jury inject --direct --template "$EXAMPLE_ROOT/output/template.txt" \
--out "$EXAMPLE_ROOT/output/rendered.txt"
printf 'EXAMPLE_VALUE={{ExampleItem/ExampleField}}\n' > "$EXAMPLE_ROOT/output/child.env"
jury exec --direct --env-file "$EXAMPLE_ROOT/output/child.env" -- \
/bin/sh -c 'test -n "$EXAMPLE_VALUE"'
jury --json run --direct --stdin ExampleItem/ExampleField --timeout 30 -- /usr/bin/wc -cThe child examples check delivery without printing the field: exec returns
the child's exit status and run reports its captured byte count. Witnessed
operations use the same field references plus the checkpoint, approval,
request/receipt output paths, and exact witness tuples shown in the walkthrough.
Inside a Git worktree, jury vault init writes only the encrypted
.jury/vault.json artifact and a fixed .jury/.gitattributes merge rule.
Identity files and authenticated local state stay in separate Linux data
and state roots. This storage layout is pre-alpha plumbing, not evidence that
Jury protects secrets.
The CLI can configure a witnessed-only policy and perform foreground governed
operations. A foreground operation publishes the complete public request,
retains its fresh protected request-session receiver only in that process,
waits for the declared approval files, obtains signed responses from the exact
witness set, and opens the exact revision only after quorum. A detached
request preview artifact remains inspectable, approvable, and cancellable, but
cannot later execute: Jury deliberately persists neither its session private
key nor witness contributions. Create a fresh foreground request instead.
Interactive approval renders the complete authenticated manifest, meaningful
item/field/path displays, and a lossless byte-escaped view of the executable,
public arguments, environment names, and typed secret targets. It does not
truncate that review to the terminal width.
jury transfer export packages
the exact encrypted vault with the bounded public policy catalog required for
fresh validation; it does not include identities, audit, checkpoints, receipts,
or private item/field names. It does include deliberately public owner-signed
review labels used for meaningful witnessed approval, and transfer inspect
reports those labels without unlocking an identity. Public inspection never
reveals field values, and import
accepts only a first installation, an identical artifact, or a complete
authenticated strict descendant that does not introduce unilateral direct slots
or weaken witnessed authority. It never merges branches. transfer status
describes only the selected identity's last successful local export and never
claims delivery or synchronization. Witness checkpoint status similarly reports
only the exact per-witness durable acknowledgements supplied to it and never
claims global freshness. Offline receipt verification proves signed public
decisions and their exact request, manifest digest, policy checkpoint, and
witness state generations. With no separately retained checkpoint, it reports
that its trust root is only the internally consistent embedded owner-signed
policy chain. Aggregate receipt reason/time fields are collector metadata unless
a verified endpoint record authenticates the receipt core. It does not prove
endpoint execution, output, non-exfiltration, or forgetting. A witnessed-only
configuration or successful request is not evidence that Jury protects real
secrets.
Artifact publication is the export commit point. If the separate local receipt
cannot be recorded afterward, export still reports the published artifact as a
success with local_export_receipt_recorded: false instead of returning an
ambiguous failure.
Jury generates registration descriptors, challenges, and proofs as canonical JSON artifacts. They are not editable configuration. Jury rejects reformatted documents, reordered keys, and added fields because registration binds their exact bytes. Each public registration input must be an absolute, direct path to a regular file owned by the current effective user. Linked files and files with group or world write permission fail validation.
For cross-user registration, transfer each generated artifact over an
authenticated channel, then have the receiving operator write a fresh file
owned by the recipient. Both principal add and principal replace require
--from DESCRIPTOR and --proof PROOF. Before changing policy, Jury checks
the selected descriptor against the candidate descriptor authenticated by the
proof.
New fields created with jury field set are concealed by default.
Updating a field preserves its existing classification unless you specify
--concealed or --unconcealed. Use --unconcealed only when that field's
value may appear in child output; its stored value remains encrypted. Existing
fields are not reclassified automatically. Inspect them with jury field list.
Concealed values must contain at least four bytes; shorter public values require
--unconcealed.
In explicit --direct mode, jury exec inherits the ordinary environment and
stdin, removes every JURY_* variable, and filters supplied concealed field
values and supported encodings from the child's stdout and stderr independently.
Unconcealed fields pass through. Redaction cannot guarantee coverage of arbitrary
encodings or transformations and does not prevent an authorized child from
retaining or transmitting plaintext.
jury run starts with a small environment allowlist and bounded output capture.
Without --timeout, runs use 1,800 seconds, reduced to the witnessed policy
limit when smaller. Witnessed exec uses the same policy-bounded default;
transparent direct exec remains unbounded. Explicit timeouts above the witnessed policy
limit are refused before publishing a request. Both commands resolve and authorize every
Item/Field reference before starting a child. Templates use {{Item/Field}}.
The slash separates exact names even when either contains dots: for example,
{{Example.Group/ExampleField}} differs from {{Example/Group.ExampleField}}.
Legacy Item.Field shorthand remains valid only when neither name contains a
dot; multi-dot shorthand is rejected. For public review labels outside the
native name profile, use a JSON pair such as '["Example Item","Example Field"]'
as the reference, or {{["Example Item","Example Field"]}} inside a template
or dotenv value. JSON escaping preserves exact labels containing quotes,
braces, dots, slashes, spaces, or Unicode. This input syntax does not require
the --json output option. Both commands support protected stdin
and sealed anonymous-file delivery, and they own the Linux process group
through cleanup.
Without --direct, read, inject, exec, and run use witnessed authority and
require an exact checkpoint, request output, receipt output, and witness
endpoint set. Governed template and child requests currently accept one item
per request, matching the frozen protocol's item scope. Governed child input is
either typed field environment/file injection or one typed stdin field;
uncommitted literal environment values and a combined stdin/environment shape
are refused. An authorized child can copy or retain every plaintext value it
receives.
$ jury request status /absolute/public/path/ExampleRequest.json
$ jury request cancel /absolute/public/path/ExampleRequest.json \
--out /absolute/public/path/ExampleCancellation.json \
--witness 'WITNESS_ID,https://127.0.0.1:7443,/absolute/private/client-token,/absolute/public/ca.pem'Each endpoint specification is
WITNESS_ID,BASE_URL,CREDENTIAL_FILE[,CA_CERTIFICATE]. HTTPS requires the
explicit CA certificate; plaintext HTTP is accepted only for a literal loopback
IP with --allow-insecure-loopback. Redirects are disabled. Credentials and
endpoint routing are deployment-local and never enter the vault, request,
manifest, or receipt.
A verified receipt proves the authenticated policy, exact request/manifest, counted independent decisions, and witness state generations encoded in it. It does not prove transport health, global freshness, endpoint execution, output, non-exfiltration, or forgetting; an authorized endpoint or child may retain plaintext. Aggregate receipt reason/time remains collector metadata unless an authenticated endpoint record covers it. These limitations are especially important because Jury is externally unreviewed pre-alpha software.
jury --json emits structured command results on stdout and one structured
error on stderr. It is a standalone flag, placed before the child's --
separator. --help and --version always return text with status 0.
| Operation | Output contract |
|---|---|
Metadata commands, including receipt verify |
Human-readable by default; JSON with --json |
read / inject with --out |
Value only in the private file; result metadata may use JSON |
read / inject with --reveal |
Raw value on stdout; --json is refused |
exec |
Streams child stdout/stderr after configured redaction; --json is refused |
run |
Bounded captured child output in the result; supports --json |
juryd |
Human-readable CLI output; its HTTP API uses JSON |
For Jury command failures, exit 2 means invalid arguments or unsupported
platform, 3 means not found, 4 conflict, 5 failed authentication, and 6 denied
access. Other runtime, storage, protection, and validation failures use 1.
Handled field-input cancellation uses 128 + signal. Successful command status
is 0. exec and run can propagate a child's nonzero status; distinguish that
from a Jury error using the command result and stderr. Parser errors never
echo supplied argument values. Streaming-command notices use stderr.
- The portable encrypted vault artifact is the source of truth.
- Inside a Git worktree, the native default is a committed
.jury/vault.json. Git transports and versions the encrypted artifact; Jury does not trust Git for authorization, integrity, or freshness. - Private identities, rollback checkpoints, local audit, recovery material, and plaintext stay outside Git.
- Secrets and access policy are scoped per item, not only per vault.
- Human users and machine workloads share one principal model.
- Governed access is revision-scoped. Before opening an item revision, the endpoint must obtain fresh approver decisions and witness contributions for the exact action manifest.
- Any direct slot is optional and unilateral. An item with one carries no quorum claim.
- Implementing witnessed cryptography requires J19A-J19C to freeze the
construction, protocol, vectors, and bounded endpoint-retention model, then
J19 to bind that exact corpus after a fresh solo verification pass. This gate
prevents drift; it is not independent security review. J19R, J19D, and J19E
are deferred external-review work and do not gate the active
0.xscope. - Jury does not claim to stop an authorized endpoint from retaining plaintext it receives.
- Jury has no external review budget. Every
0.xrelease remains explicitly externally unreviewed, pre-alpha, and unsuitable for real secrets.
See docs/architecture.md for the initial boundaries and
docs/naming.md for the deliberately limited product metaphor.
The standalone witness and independent external-anchor deployment are documented
in docs/self-hosting-juryd.md.
The pre-alpha owner backup, restore, and ExampleVault drill procedure is in
docs/recovery.md.
The implementation sequence and security decisions live in
docs/jury-v1-master-plan.md. The downstream Jig
integration remains separate in
docs/jig-cutover-plan.md.
The first 0.x release targets Linux through the jury CLI and a self-hosted
juryd. The active scope defers macOS, Windows, the jury-tui,
hardware-backed identity protectors, managed-service topology, semantic Git
merge, and Jig-vault import. J18 rollover and suite migration are included in
Linux 0.0.1 and gate the final release candidate. The implementation has direct
and governed jury vault rollover flows with fresh backup,
transfer, explicit local adoption and exact-candidate recovery. Historical
bootstrap validation retains the original role proofs, policies and labels.
The checkout also implements explicit jury vault migrate-suite --to 2, using
AES-256-GCM HPKE under the accepted supplemental input gate. It re-encrypts
active items into a new lineage and preserves the original copies. Core direct
and governed migration tests pass, including native backup restore and witnessed
destination reads. These paths remain externally unreviewed pre-alpha software.
Capacity exhaustion
fails closed before mutation. Divergent Git artifacts
require explicit operator recovery.
| Package | Responsibility |
|---|---|
jury |
The jury command-line interface |
jury-core |
Vault-domain rules and cryptographic orchestration boundaries |
jury-protocol |
Witness request, approval, response, and receipt contracts |
jury-tui |
Deferred terminal-interface scaffold; not shipped in the first 0.x |
jury-witness |
juryd HTTP, SQLite, identity, and external-anchor adapters |
jury-process |
Linux child delivery, redaction, and process-group cleanup |
jury-filesystem |
Hardened path, file, and atomic-publication operations |
jury-protected |
Bounded protected-memory primitives |
Jury is standalone and must not depend on Jig. Jig may eventually consume Jury through its public CLI, library, or protocol interfaces.
scripts/jig bootstrap
scripts/jig check fmt
scripts/jig check clippy
scripts/jig check testThe repository uses Jig for repeatable development checks. Jig is not a runtime dependency.
Jury is source-available, free to self-host under the
Elastic License 2.0 (ELv2), SPDX identifier Elastic-2.0. This applies
to the core, protocol, CLI, TUI scaffold, and witness server. ELv2 permits use,
modification, and redistribution subject to its conditions, including the
restriction on hosted or managed services that expose a substantial set of
Jury's features or functionality to third parties. Jury is not open source.
See the licensing guide, copyright and third-party notice, and contribution requirements. Licensing permission does not change Jury's pre-alpha status or make it suitable for real secrets.