Valid9 Alpha

Developer documentation

Meet v9.

Read workspace records, plan delivery work, prepare quality drafts and bring existing records into Valid9 from your terminal.

Install during the alpha

Public downloads and Homebrew installation are not available yet. The first signed release is being prepared. Contact hello@valid9.com for alpha CLI access. The source-build path below requires access to the private Valid9 API repository.

For contributors with repository access, install Go 1.26 or later and build the customer executable:

git clone git@github.com:valid9d/valid9-api.git
cd valid9-api/backend
go build -o ./v9 ./cmd/v9
./v9 --help

The result is a standalone executable; it does not need a repository checkout at runtime. Move it into a directory on your PATH to use v9 as shown below, or use ./v9 from the build directory. A local build reports dev from v9 --version. This is the customer CLI; v9ops is separate operator tooling.

Coming with the first release

Not available yet. These steps will work once the first signed release is published. Downloads and release notes will appear in the valid9d/v9cli repository.

On a Mac with Homebrew:

brew install --cask valid9d/tap/v9
v9 --version

Or install manually. Download the archive for your platform (darwin_arm64, darwin_amd64, linux_arm64 or linux_amd64) and the release’s checksums.txt. Check the archive with shasum -a 256 on macOS or sha256sum on Linux and compare the whole hash with its entry in checksums.txt. Then extract it and place v9 in a directory on your PATH; Go is not needed. Mac builds will be signed and notarized. If macOS reports a verification failure, contact us; do not disable Gatekeeper.

Sign in to your workspace

First enroll an authenticator in the Valid9 app. Ask your workspace administrator or Valid9 support for the environment’s API origin, authentication origin and public publishable key. Replace the uppercase placeholders:

v9 auth login \
  --api https://YOUR-API-ORIGIN \
  --auth-url https://YOUR-PROJECT.supabase.co \
  --publishable-key sb_publishable_YOUR_PUBLIC_KEY \
  --email you@company.com
v9 organizations

Your password and authenticator code are entered at hidden terminal prompts. Use the public publishable key, never a database credential or a service-role key.

The CLI stores its session in your operating system’s user configuration directory at v9/session.json, with private file permissions and refresh-token rotation. A session saved by an earlier build under v9cli/session.json is picked up automatically. Keep it out of source control and chat. Use the global --session /private/path/session.json option on each command when keeping a separate staging session.

Sessions follow the app’s sign-in rules: sign in again after about an hour without use, or 12 hours after you signed in.

Use readable names and short IDs

Run v9 organizations to find your organization’s organization_slug and UUID. Every --organization option accepts either. The examples below use acme as an illustrative slug: replace it with yours, and replace example record references with records in that organization.

Permanent record references
RecordExample
RequirementREQ-12
TaskTASK-34
TestTEST-8
Test runTR-19
ReleaseREL-3
CAPACAPA-7
v9 requirements get --organization acme --requirement REQ-12
v9 requirements discussion --organization acme --requirement REQ-12
v9 references resolve --organization acme --reference TEST-8
v9 references resolve --organization acme --reference TR-19
v9 releases deliverables --organization acme --release REL-3
v9 capa get --organization acme --capa CAPA-7

Requirement, task, test, release and CAPA options accept their matching short ID or UUID. This includes requirement parents, test filters and the tasks included in a release. Short IDs ignore case and belong to the organization you select; the same REQ-12 can name a different record in another organization. Resolution never switches organizations for you.

A requirement or test short ID supplies its module; a task short ID supplies its team for edits; a CAPA short ID supplies its team, so --team is optional with --capa CAPA-7. An explicitly conflicting module or team is refused. UUID-only inputs keep their existing scope requirements. Creating a requirement still needs a module, and creating a task still needs a team. Modules, teams, documents, sprints, people and other record types still use UUIDs.

references resolve returns the record’s UUID and navigation context for all six prefixes, including archived test runs and closed CAPAs. It does not complete a run or publish a release. JSON import and assessment files retain their existing schemas; shorthand applies to command options, not arbitrary file contents.

Use a current alpha build and an environment with readable-reference support deployed. If an older client only accepts UUIDs, those remain valid. Read how references and shared links work.

Find your records

Use your organization slug or UUID. Select module and team UUIDs from their respective lists:

v9 teams list --organization acme
v9 modules list --organization acme
v9 requirements list --organization acme --module MODULE_UUID --limit 20
v9 tests list --organization acme --requirement-id REQ-12
v9 teams workspace --organization acme --team TEAM_UUID
v9 releases deliverables --organization acme --release REL-3
v9 sops list --organization acme --team TEAM_UUID
v9 assurance list --organization acme --kind systems

Commands print JSON; lists print one record per line. Lists fetch all pages unless you specify --limit (1–100). Use --offset to skip records.

The same session reads people, search results, controlled documents, deliverables and quality processes. One example per group:

v9 people list --organization acme
v9 search --organization acme --query RM-123
v9 documents records control --organization acme --team TEAM_UUID --kind sops --record SOP_UUID
v9 deliverables version --organization acme --deliverable DELIVERABLE_UUID --number 2
v9 capa list --organization acme --team TEAM_UUID --status plan_review
v9 actions --organization acme --summary
v9 training assignments --organization acme --team TEAM_UUID --mine
v9 resources list --organization acme --category equipment
v9 audit events --organization acme --record RECORD_UUID
v9 audit verify --organization acme
v9 validation-packages list --organization acme

people list shows who can be named as a reviewer or assignee. search finds records by text, type, status, team or module and dates, including native short IDs and Jira and AIO Tests keys kept from an import. actions lists your own current work. audit verify recomputes the audit hash chain and exits non-zero when it is broken. Run v9 <group> --help for each group’s commands and flags.

Plan delivery work

Requirements sit at the user, functional or design level, each under a parent one level up in the same module. Rate user requirements with --severity, --probability and --detectability, each from 1 (remote) to 4 (high); Valid9 derives the risk class. Functional and design requirements take the class of the user requirement above them. A requirement’s state is derived from its tasks and test runs, so there is no status to set.

v9 requirements create --organization acme --module MODULE_UUID \
  --title 'Learners attest completion' --severity 3 --probability 2 --detectability 3
v9 requirements create --organization acme --module MODULE_UUID \
  --title 'Attestation form' --level functional --parent REQ-12
v9 tasks create --organization acme --team TEAM_UUID --title 'Attestation API' \
  --status todo --requirement REQ-12 --risk-likelihood medium --risk-impact high
v9 sprints create --organization acme --team TEAM_UUID --title 'Sprint 1' \
  --goal Attestation --start 2026-10-01 --end 2026-10-14
v9 tasks move-team --organization acme --task TASK-34 --to-team OTHER_TEAM_UUID \
  --expected-version 1
v9 tasks update --organization acme --team OTHER_TEAM_UUID --task TASK-34 \
  --sprint SPRINT_UUID --expected-version 2
v9 releases create --organization acme --title 26.1 --task TASK-34 --description 'Attestation improvements'
v9 releases set-system --organization acme --release REL-3 --system SYSTEM_UUID
v9 releases set-approver --organization acme --release REL-3 --approver QUALITY_UUID
v9 releases classify --organization acme --release REL-3 --classification minor

Moving a requirement to another level or parent needs --retest, or a --move-rationale explaining why its test evidence still holds.

Coming with the sprint planning update: required task ratings and tasks move-team need the companion API deployment and an updated CLI build. Staging and production availability have not yet been verified.

Every task is rated for risk likelihood and impact (low, medium or high) when it is created and enters the backlog. A task created before ratings were required is rated on its next save.

Sprint planning assigns backlog tasks to teams and sprints. tasks move-team moves a backlog task that is still to do and has no test runs to another team; it keeps its ratings and short ID, and its assignee only if they are on the new team. Moving a task to a team is not an approval and is audited. Moving a task into a sprint approves it in your name, at its rating. Changing an approved task’s title, requirement or description while it is in a sprint approves it again and needs --reason.

Releases are saved as drafts. Choose the system the release validates and the Quality member who approves its deliverables. A Quality member classifies a draft release as major, minor or patch with releases classify, which decides the deliverables it needs.

Organize releases, requirements and tasks

Coming with the record organization update: these commands require the companion API deployment and an updated CLI build. They are prepared here for rollout; staging and production availability have not yet been verified.

In the app, drag an order handle to arrange releases, requirements within a module, or tasks within their current backlog/sprint group or board column. Move buttons and Alt+Up/Down are alternatives. The order is shared with your organization and survives reload. Ordering does not change risk, approvals, status, content revisions or test evidence.

Release descriptions are optional. On draft create/update, use --description; omitting it preserves the existing text, and --description '' clears it. A published description uses the existing signed correction in the app.

Archive a draft or published release to hide it from the normal list and search. Show archived releases and search’s archived filter expose it for restoration. Its records, publication, direct links, inspection package and evidence remain available. Archiving does not archive its runs or remove failures from readiness checks.

v9 releases list --organization acme
v9 releases move --organization acme --release REL-3 --before REL-1 --expected-version 0
v9 releases archive --organization acme --release REL-2 --expected-version 1
v9 releases restore --organization acme --release REL-2 --expected-version 2
v9 requirements order --organization acme --module MODULE_UUID
v9 requirements move --organization acme --requirement REQ-12 --before REQ-4 --expected-version 0
v9 tasks order --organization acme --team TEAM_UUID
v9 tasks move --organization acme --task TASK-34 --last --expected-version 0

Replace these example versions with the current list version, initially zero, from release_organization.version in releases list or the scoped order command. It is separate from a record’s content revision. Every move, archive or restore increments it; on conflict, read again and review before retrying. Choose either --before or --last. Authors and administrators can save order and archive state; all active members can read them. These changes are audited with an optional reason.

Edit records

Read before editing. Every edit needs the record’s current --expected-version. A stale version returns a conflict; read the latest record and review the change before retrying. Nothing can be deleted.

tasks update keeps every value you leave out. Use --backlog to move a task out of its sprint (it keeps its approval), --clear-assignee to unassign it and --description '' to clear its description:

v9 tasks update --organization acme --team TEAM_UUID --task TASK-34 \
  --backlog --clear-assignee --expected-version 3

Module, requirement, test, procedure, sprint, release and document-draft updates replace the supported fields as a set, so include the existing values for fields you want to keep. A requirement keeps its level, parent and rating unless you change them. A release update needs --task for each task, or --no-tasks. Its description is preserved when omitted.

Test steps, procedure drafts and document drafts are supplied as JSON files. A test-step file contains objects with action and expected and replaces every step. A procedure file contains title, purpose, scope, responsibilities and procedure. A document file contains title, document_type, owner, summary and content. Unknown fields are refused.

--reason is optional. When you give one, the audit trail keeps it; without one, it records what was done. A few commands require a reason because they change an approved record or remove something from use: capa revise-plan, documents records revise, resources retire and resources restore, as well as changes to an approved task described above, and correcting a completed test run you performed with runs correct or runs evidence add (corrections). A CAPA comment is its own text. runs affirm needs a --rationale, which is the record of the judgment (stale test runs).

Your role and the record’s state still determine what you can change.

Prepare quality work

Draft CAPA work, controlled documents, training assignments and shared resources:

v9 capa open --organization acme --team TEAM_UUID --title 'Label deviation' \
  --description '...' --classification deviation --containment 'Quarantined' \
  --owner OWNER_UUID --reviewer QUALITY_UUID
v9 capa investigate --organization acme --team TEAM_UUID --capa CAPA_UUID \
  --root-cause '...' --effectiveness-plan '...' --expected-version 1
v9 documents records create --organization acme --team TEAM_UUID --file doc.json
v9 documents records revise --organization acme --team TEAM_UUID --kind sops --record SOP_UUID \
  --expected-record-version 3 --expected-control-version 4 --reason 'Periodic review found a gap'
v9 training assign --organization acme --team TEAM_UUID --record SOP_UUID \
  --revision EFFECTIVE_EVENT_UUID --learner USER_UUID
v9 resources create --organization acme --category equipment --code PRN-7 --name 'Label printer 7'

CAPA drafting continues with add-action, comment, revise-plan, request-effectiveness, link-resource, unlink-resource, reassign-owner and reassign-action. training assign takes the revision from documents records control and the learner from training learners; the training is due in 7 days and the learner is emailed. Shared resources can also be revised, retired and restored. Supplier and system drafts use assurance create, save and generate-plan.

Download exports and controlled copies

v9 export organization --organization acme --out records.zip
v9 export suppliers --organization acme --out supplier-register.json
v9 export systems --organization acme --out system-register.json
v9 releases package --organization acme --release REL-3 --out package.zip
v9 deliverables pdf --organization acme --deliverable DELIVERABLE_UUID --number 2 --out TP-7.pdf

Each command writes to a file that must not exist yet, checked before downloading. releases package downloads a published release’s inspection package. Organization exports, deliverable PDFs and release packages are recorded in the audit trail. These files are available from the CLI, not through MCP.

Stale test runs

When a requirement or test changes after a run, the run is stale: it no longer counts as evidence, and the release it belongs to can’t be published until the evidence is affirmed or the test is run again. Read the change first:

v9 runs revision --organization acme --run TR-19

The result shows the requirement and test before and after, what you can do (offer) and why, and the run’s earlier affirmations. When a completed run’s test steps are unchanged in number and order, an author or administrator can affirm, as themselves, that its evidence still holds. Give the versions you judged and a rationale:

v9 runs affirm --organization acme --run TR-19 --expected-version 2 \
  --test-version 3 --requirement-version 2 \
  --rationale 'The edit clarifies the timeout; step 2 still verifies it.'

v9 shows you the run and the revisions and asks you to confirm at your terminal. There is no option to skip the question, and without a terminal the command is refused, so a script or an assistant’s shell can’t affirm for you. A change made after you read it is refused with a conflict. Read it again before you affirm. A second person then reviews the run again in Valid9, and it can’t be you. Move a stale draft run to the current revision with runs move, using the same version options. Results on steps whose wording changed are cleared. When the steps changed in number or order, run the test again in Valid9.

Test-run evidence

Requires the next release. runs evidence and runs correct ship with the next published v9 release and need the matching API in your environment. Check v9 runs --help.

List a run’s evidence files. Each one shows its ID, step, name, size, SHA-256 digest, uploader, time and reason:

v9 runs evidence list --organization acme --run TR-19

Attach one file to a numbered step of a draft run. Any author or administrator can do this, including on a run someone else started. The reason is optional:

v9 runs evidence add --organization acme --run TR-19 --step 2 \
  --file ci-evidence-report.pdf --reason 'CI evidence report for the session tests'

A file can be up to 10 MiB, with up to five files per step and 100 MiB of test-run evidence per organization. Each file is attributed to you. Files are never replaced or removed, and the same file can’t be attached to the same step twice. A wrong file calls for a new run, not a removal. Archived runs can’t gain evidence; restore the run first.

Download one file, using its id from runs evidence list. The output file must not exist yet:

v9 runs evidence download --organization acme --run TR-19 \
  --evidence EVIDENCE_UUID --out session-tests-report.pdf

Cite automated CI tests

When a step cites automated tests that ran in CI as its evidence, make the evidence traceable on its own. In the step’s actual result, link each test at the exact commit that was tested and link the CI run or job that passed. Then attach a CI evidence report file to the step, so the result stays with the run even if the CI system’s logs expire. For example:

Passed: TestRefusesUnverifiedSession
  https://github.com/acme/api/blob/4f2c9e1/auth/session_test.go#L40
CI job (passed): https://github.com/acme/api/actions/runs/123456/job/789
Report attached to this step: ci-evidence-report.pdf

Correct a completed test run

A completed run is never edited, only corrected, with a reason. Only the person who performed the run can correct it. Correct one step at a time: its actual result, its status, the evidence files it should have had, or any of these together:

v9 runs correct --organization acme --run TR-121 --step 1 \
  --actual-file actual.txt --evidence tr-121-ci.txt \
  --reason 'Step 1 cited CI tests without their commit, job or report'

Use --actual for a short actual result or --actual-file to read it from a file. The status is passed, failed or blocked; leave it out to keep the step’s outcome. Repeat --evidence for each file (up to five per step). You can add files without changing the step’s text or status. The run’s other steps are kept as recorded, and the same reason goes with each file.

To add a single file to a completed run, you can also use runs evidence add as above. On a completed run it is a correction: --reason is required.

Correcting is a personal decision, so v9 asks you once at your terminal for the whole correction. It shows the step before and after, or only what is added when the new actual result extends the old one, and each file’s size and SHA-256 digest. There is no option to skip the question, and without a terminal the command is refused, so a script or an assistant’s shell can’t correct a run for you. Each correction is audited with your reason and the run before and after. The run’s existing review is no longer current: a second person reviews it again in Valid9. A published release that cites the run shows it as having corrected evidence; the release keeps what it froze until Quality corrects the release.

In the Valid9 app, open the completed run and select Correct this test run, enter the reason, then correct results or attach a file in Evidence.

What stays in the Valid9 app

Personal decisions have no command. Make them in Valid9:

For test runs, see completion and retention in the app, including the passed-only list shortcut and handling failed or blocked results.

  • signing records, executing and completing test runs and deciding reviews, including run reviews;
  • generating, sending, approving or rejecting release deliverables, and publishing releases;
  • sending, approving, rejecting or retiring controlled documents and SOPs;
  • submitting, approving or signing supplier and system assessments;
  • submitting a CAPA plan, completing CAPA actions and the reviewer’s CAPA decisions;
  • completing or cancelling training;
  • changing members and connecting apps.

The CLI acts as you, so it can do things a connected app cannot: move a task into a sprint, which approves it; for a Quality member, classify a draft release; and, each confirmed at your terminal, affirm or move a stale run and correct a completed run you performed, including adding its evidence. None of these is a signature. Executing and completing runs and reviewing them stay in Valid9.

Import document exports

For retained previews, use v9 import documents upload --organization acme --team Quality --format qualio --inventory documents.csv --bundle export.zip, then get, apply, history and replan. Portable inventories use --format portable --source legacy-qms. See formats, limits and recovery, including rollout availability. The offline workflow below remains supported.

Local Qualio preparation

Start with the CSV inventory and the matching document ZIP bundles from Qualio. Keep the original exports. Prepare a local plan, review it, validate with a dry run, then import into an explicitly chosen organization and team:

v9 documents prepare --inventory effective-documents.csv \
  --bundle batch-1.zip --bundle batch-2.zip --out prepared
v9 documents import --organization acme --team TEAM_UUID \
  --plan prepared/plan.json --reason 'Migrate quality documents' --dry-run
v9 documents import --organization acme --team TEAM_UUID \
  --plan prepared/plan.json --reason 'Migrate quality documents'
v9 documents list --organization acme --team TEAM_UUID

Preparation and dry-run validation work offline. The import retains original files and source revision details, and creates Valid9 drafts. Source approvals and effective dates remain provenance; importing does not approve, sign or make the new records effective.

Missing primary files block preparation by default. Use a fresh output directory for each plan and compare import receipts with your source inventory before declaring the migration complete. Identical retries return the existing receipt; changed content for the same source revision is refused.

Use v9 documents download --help to retrieve retained originals with digest verification. The training commands also prepare and import supported historical training evidence; use their help text and review your source format with our team before migrating.

Import Jira files (AIO optional)

The primary workflow is v9 import jira upload --organization acme --jira jira.csv --mapping mapping.json. Inspect with get and list, revise with map, refresh with replan, and apply the reviewed --expected-version. Add --accept-skipped only after reviewing skips. history reads retained revisions. No AIO subscription or Jira connection is needed. See the complete file-import workflow and its alpha rollout note.

Legacy local workflow

Bring current requirements, tests and unreleased tasks across from files you export from Jira (CSV) and AIO Tests (CSV or JSON). The CLI reads the files only. It never connects to Jira or AIO Tests and needs no credentials for them. Each record keeps its Jira or AIO Tests key as a read-only external ID, which search finds.

A mapping file in YAML or JSON says how your data fits Valid9: which issue types are requirements and tasks, how a requirement’s level is decided, which fields hold acceptance criteria and risk ratings, which statuses are unreleased, and the destination module and team. For example:

module: Product
team: Team
requirements:
  issue_types: [Requirement]
  level:
    labels: {UR: user, FR: functional, DS: design}
tasks:
  issue_types: [Story, Bug]
  statuses: {To Do: todo, In Progress: in_progress, In Review: qa, Done: done}
  risk_likelihood: medium
  risk_impact: medium
v9 import jira-aio plan --jira jira.csv --aio aio.csv --map mapping.yaml --organization acme
v9 import jira-aio preflight --jira jira.csv --aio aio.csv --map mapping.yaml --organization acme
v9 import jira-aio apply --jira jira.csv --aio aio.csv --map mapping.yaml --organization acme \
  --report-dir reports --attach-report
v9 import jira-aio history --organization acme --source aio --files 'AIO execution report 26.0911.pdf'

plan and preflight write nothing. apply refuses to write while the plan has an error and is safe to run again. It writes an import report with each input file’s checksum and each record’s Valid9 ID and key; keep it as your data-migration evidence. --attach-report files it in the team’s documents.

Tasks go to the backlog, never into a sprint, and every task is rated as it is imported. Rate tasks from Jira columns with tasks.risk_likelihood_field and tasks.risk_impact_field, or give every imported task a rating with tasks.risk_likelihood and tasks.risk_impact (low, medium or high). A column value is used first. A task the mapping doesn’t rate is an error in the plan: the import never assumes a rating. Use history to keep earlier history, such as AIO Tests execution reports and Jira exports, as imported documents. Results are not recreated as test runs, and Jira approvals are not recreated as signatures.

Common fixes

  • Sign-in fails: verify the API, authentication origin and public key belong to the same environment, and that your authenticator is enrolled.
  • Asked to sign in again: sessions end after about an hour without use or 12 hours after sign-in. Run v9 auth login again.
  • Access denied: check your active membership, role and selected organization.
  • Reference not found or rejected: check the organization, environment and prefix. Use v9 references resolve to inspect a short ID. Do not pass a task reference to a requirement option, or a conflicting module/team.
  • Conflict (409): fetch the current version, compare changes and retry deliberately.
  • Evidence file or correction refused: check the limits (10 MiB per file, five files per step, 100 MiB per organization) and whether that file is already on the step. Archived runs can’t gain evidence. A completed run can be corrected only by the person who performed it, with --reason, from an interactive terminal.
  • Import interrupted: rerun with the same reviewed plan and destination; retain the receipts and reports.
  • Command missing: check v9 --help and v9 --version, and confirm which alpha build you have with support.