diff --git a/.cli-flags.toml b/.cli-flags.toml
new file mode 100644
index 0000000..fc214a2
--- /dev/null
+++ b/.cli-flags.toml
@@ -0,0 +1,86 @@
+[help]
+url = "https://github.com/ORESoftware/tarballs-cli/issues/1"
+columns = ["options", "env", "type", "default", "description"]
+
+[parse]
+command_env = "TRBL_COMMAND"
+positionals_env = "TRBL_POSITIONALS"
+unknown_options_env = "TRBL_UNKNOWN_OPTIONS"
+errors_env = "TRBL_PARSE_ERRORS"
+allow_unknown = false
+
+# This manifest is the intended migration contract. The legacy shell dispatcher
+# does not yet consume it; issue #1 remains open until flags-2-env is the single
+# argv parser and the command-specific positional schemas are enforced.
+
+[flags.help]
+env = "TRBL_HELP"
+aliases = ["help"]
+short = "h"
+type = "bool"
+default = false
+help = "Print generated help and exit without performing repository effects."
+
+[flags.version]
+env = "TRBL_VERSION_REQUESTED"
+aliases = ["version"]
+type = "bool"
+default = false
+help = "Print the CLI version and exit."
+
+[flags.dry_run]
+env = "TRBL_DRY_RUN"
+aliases = ["dry-run", "plan"]
+type = "bool"
+default = true
+help = "Plan the command without changing files, Git repositories, or remotes."
+
+[flags.json]
+env = "TRBL_JSON"
+aliases = ["json"]
+type = "bool"
+default = false
+help = "Emit bounded machine-readable diagnostics without credentials or file contents."
+
+[flags.repository_root]
+env = "TRBL_REPOSITORY_ROOT"
+aliases = ["repository-root", "repo-root"]
+type = "string"
+help = "Explicit local repository-store root; it must pass ownership, symlink, and traversal checks."
+
+[flags.lock_timeout_ms]
+env = "TRBL_LOCK_TIMEOUT_MS"
+aliases = ["lock-timeout-ms"]
+type = "integer"
+default = 10000
+help = "Maximum time to wait for a local repository lock before failing closed."
+
+[commands.init]
+help = "Register and clone one approved remote into the managed local repository store."
+
+[commands.use]
+help = "Select an already registered repository without mutating a shell profile."
+
+[commands.add]
+help = "Plan or copy one local artifact into an approved relative destination."
+
+[commands.get]
+help = "Resolve one registered artifact without evaluating remote content."
+
+[commands.view]
+help = "Show bounded metadata for the active repository and tracked artifacts."
+
+[commands.fetch]
+help = "Fetch immutable remote metadata for one registered repository."
+
+[commands.push]
+help = "Push reviewed local commits to an explicitly configured remote without force."
+
+[commands.repair]
+help = "Validate and repair local metadata without deleting repositories or rewriting history."
+
+[commands.remove]
+help = "Remove one registration after a plan and confirmation; remote state is unchanged."
+
+[commands.remove-all]
+help = "Plan removal of all local registrations; remote repositories and refs are unchanged."
diff --git a/AGENTS.md b/AGENTS.md
new file mode 100644
index 0000000..1638371
--- /dev/null
+++ b/AGENTS.md
@@ -0,0 +1,45 @@
+# Repository agent instructions
+
+Read and obey the current organization baseline and [`ORESoftware/my-ai/AGENTS.md`](https://github.com/ORESoftware/my-ai/blob/main/AGENTS.md) before changing this repository. Where rules differ, follow the stricter rule.
+
+## Current repository state
+
+`tarballs-cli` / `tarzan` is a legacy shell-dispatched CLI under migration review in [issue #1](https://github.com/ORESoftware/tarballs-cli/issues/1). Do not describe it as modernized, Zed-published, reproducible, or production-ready until that issue's completion evidence exists.
+
+## Release and installation freeze
+
+- Do not publish the npm package, create a Zed release, add another package registry, or restore install-time side effects while issue #1 is open.
+- Installation must not write to a user's home directory, mutate shell profiles, clone repositories, contact remotes, or read credentials.
+- Do not bypass the `private` package guard or the prepublish blocker added during the migration gate.
+- A release-enabling change requires an explicit migration/retirement decision, consumer evidence, green packaging tests, reviewed immutable dependency receipts, and a separate pull request.
+
+## Command and input boundary
+
+The intended command vocabulary is defined in root `.cli-flags.toml`. New runtime work must use the reviewed `flags-2-env` integration as the only argv parsing/coercion boundary. Reject unknown commands, flags, and extra positional arguments. Treat filenames, repository identifiers, refs, remote URLs, archive paths, and environment values as untrusted input.
+
+Before any command performs an effect, validate:
+
+- path traversal, symlink escape, special-file, ownership, and destination constraints;
+- remote URL scheme/host/userinfo and credential absence;
+- command and ref syntax without shell re-parsing;
+- concurrency, lock, interruption, and idempotency behavior;
+- dry-run output and diagnostic redaction.
+
+Never use `eval`, concatenate untrusted shell commands, place credentials in URLs or process arguments, or log SSH keys, tokens, credential-helper output, repository contents, or raw provider errors.
+
+## Git and repository effects
+
+Keep remote writes behind an explicit effect adapter and an opt-in command. Default tests must use temporary local repositories and must not contact GitHub or another registry. Do not force-push, rewrite history, delete remote refs, or overwrite non-empty destinations. Preserve concurrent work and resolve conflicts semantically; never choose one side wholesale.
+
+## Migration sequence
+
+1. Inventory consumers and commands actually in use.
+2. Add characterization and adversarial tests around the current public behavior.
+3. Replace the shell dispatcher incrementally with a maintained runtime.
+4. Integrate flags-2-env once at process entry.
+5. Add immutable Zed metadata and dependency receipts without publishing.
+6. Prove non-interactive packaging/install behavior in an isolated home directory.
+7. Obtain review of the retirement or migration decision.
+8. Enable release only in a dedicated, exact-head, least-privilege pull request.
+
+Do not hand-edit generated artifacts or claim checks that were not run. Pull requests must link issue #1 and the corresponding Linear work, describe rollback and consumer impact, and remain draft while release, migration, or destructive behavior is unresolved.
diff --git a/docs/migration-decision.md b/docs/migration-decision.md
new file mode 100644
index 0000000..0a83411
--- /dev/null
+++ b/docs/migration-decision.md
@@ -0,0 +1,135 @@
+# Tarzan / tarballs-cli migration decision
+
+Tracking: [ORESoftware/tarballs-cli#1](https://github.com/ORESoftware/tarballs-cli/issues/1) · Linear: `DEN-3944`
+
+## Current disposition
+
+**Freeze the legacy package while preparing a migration.** Do not publish, archive, delete, or silently revive the current implementation.
+
+This repository still contains useful command intent, but the present shell dispatcher, global active-repository state, direct Git effects, install-time home-directory write, old CI assumptions, and missing parser/security tests are not an acceptable release boundary. The freeze preserves source and consumer compatibility evidence while preventing another npm publication from being mistaken for a supported release.
+
+The branch implementing this decision:
+
+- marks the package private;
+- removes the npm `postinstall` entry that writes under `$HOME`;
+- adds a fail-closed `prepublishOnly` blocker;
+- records repository-local agent and credential rules;
+- declares the intended command vocabulary in `.cli-flags.toml` without claiming the legacy shell dispatcher consumes it.
+
+## Why migration is preferred over immediate archive
+
+The source contains ten named workflows—`init`, `use`, `add`, `get`, `view`, `fetch`, `push`, `repair`, `remove`, and `remove-all`—and historical documentation describes an artifact-to-Git repository workflow. Before retirement, the owner must know whether any scripts, CI images, globally installed packages, aliases, or repositories still rely on those names and storage conventions.
+
+An immediate archive could strand consumers or erase useful behavior before it is mapped to `zed-pkg`, an artifact-storage client, or another maintained home. Conversely, the presence of source is not evidence that every command should survive. The migration must inventory actual use and preserve only justified behavior.
+
+## Consumer inventory receipt
+
+The inventory must be machine-readable and bind its result to immutable source evidence. At minimum it records:
+
+- audit start/end time and actor/workflow identity;
+- exact GitHub organizations, repositories, default-branch SHAs, package registries, images, and local configuration roots searched;
+- every reference to `tarballs-cli`, package name, `tarzan`, `trbl`, `$HOME/.trbl`, and `$HOME/.oresoftware/bash/tarzan.sh`;
+- whether the reference installs, invokes, documents, vendors, or merely mentions the CLI;
+- inaccessible repositories, pagination limits, excluded private surfaces, and stale results;
+- proposed replacement and migration owner for each active consumer;
+- content digest of the normalized receipt.
+
+A partial search is reported as partial. Absence cannot be inferred from inaccessible organizations, local machines, registries, or images.
+
+## Runtime migration contract
+
+The maintained runtime must use `flags-2-env/flags-2-env@0.3.0` as the sole argv parsing and coercion boundary. The root `.cli-flags.toml` is the reviewed command vocabulary, but command-specific positional schemas and compatibility aliases still require implementation and tests.
+
+Architecture:
+
+```text
+argv + environment
+ -> flags-2-env parse/validation
+ -> immutable command value
+ -> pure validation and effect plan
+ -> filesystem/Git adapter
+ -> bounded redacted receipt
+```
+
+The parser rejects unknown flags, invalid coercions, unsupported commands, and excess positionals. Defaults do not override explicit environment values. The domain layer never rereads process argv/environment.
+
+## Effect and security requirements
+
+Before any file or Git effect:
+
+- canonicalize an explicitly allowed base without following an attacker-controlled final symlink;
+- reject traversal, absolute destination paths where relative paths are required, special files, symlink escape, and ownership/mode violations;
+- validate repository identifiers and refs with closed grammars;
+- permit only reviewed remote URL schemes/hosts and reject userinfo, fragments, encoded credentials, ambiguous scp-like forms, link-local/metadata targets, and control characters;
+- construct subprocess argv arrays without shell interpolation or `eval`;
+- acquire a per-repository lock with bounded timeout and stale-lock recovery evidence;
+- stage effects in a run-scoped directory and promote atomically where possible;
+- make interruption/retry behavior explicit and idempotent;
+- prohibit force pushes, destructive history rewrites, and remote deletion;
+- redact tokens, SSH material, credential-helper output, home paths, file contents, and raw provider errors.
+
+`dry-run` is the default in the declared contract. An apply path requires a deliberate opt-in plus an immutable plan or confirmation mechanism. Tests use temporary local repositories and fake remotes; no default test contacts GitHub.
+
+## Install and package requirements
+
+A future installation must:
+
+- perform no network, repository, shell-profile, home-directory, or credential effect during package-manager lifecycle hooks;
+- install only reviewed package files;
+- be reproducible from a clean checkout and immutable dependency receipt;
+- run smoke tests with an isolated temporary `HOME`;
+- verify `npm pack --dry-run` / equivalent output and prohibit secrets, local state, test credentials, caches, and legacy CI artifacts from the package;
+- publish only from an exact reviewed commit through a least-privilege workflow;
+- produce an immutable npm/Zed release receipt and rollback/deprecation plan.
+
+The old `assets/postinstall.sh` source is retained only as migration evidence; it is no longer invoked by npm. Removing it from history is neither necessary nor authorized.
+
+## Zed ownership decision
+
+Before adding `.zpkg.toml`, decide which package owns the behavior:
+
+1. a command group inside `zed-pkg` when this is fundamentally package/artifact resolution;
+2. a dedicated artifact-storage client when it manages generic immutable artifacts;
+3. a reduced `tarballs-cli` successor when independent command/product ownership remains justified.
+
+Do not duplicate upload/resolution policy across homes. The chosen owner must expose an immutable source revision, dependency lock/receipt, compatibility mapping, and consumer migration plan. Zed metadata may be staged only after that decision; metadata alone cannot close #1.
+
+## Test gates
+
+The migration PR cannot become ready until tests cover at least:
+
+- every command and help/error path;
+- missing, duplicate, unknown, and excess arguments;
+- traversal, absolute paths, symlink races/escape, hard links, special files, and permission failures;
+- remote URL credentials, fragments, control characters, unsupported schemes, host allow/deny policy, and command injection;
+- interrupted clone/fetch/copy/commit/push sequences;
+- concurrent writers, lock timeout, stale lock, and idempotent retry;
+- dirty repositories, moved heads, non-fast-forward updates, merge conflicts, and rejected force behavior;
+- redaction of environment, URLs, errors, paths, and subprocess diagnostics;
+- isolated install with no writes outside the package target;
+- deterministic dry-run and receipt output;
+- behavior comparison for every command retained from the legacy CLI.
+
+## Release, retirement, and closure gates
+
+Issue #1 remains open. It may close only after one of these receipts is reviewed:
+
+### Migration
+
+- complete consumer inventory;
+- approved ownership decision;
+- maintained runtime and flags-2-env integration;
+- green exact-head tests and reproducible packaging;
+- immutable Zed/npm release receipt;
+- consumer migration evidence and rollback/deprecation plan.
+
+### Retirement
+
+- complete consumer inventory;
+- named replacement or explicit no-replacement rationale;
+- package deprecation and publishing disablement evidence;
+- documentation/redirect plan;
+- owner-approved archive timing;
+- salvage record for unique tests, contracts, and command behavior.
+
+Until then, the safe repository state is preserved source plus blocked release/install side effects—not a new production release.
diff --git a/package.json b/package.json
index 146208c..947516d 100755
--- a/package.json
+++ b/package.json
@@ -1,7 +1,8 @@
{
"name": "tarballs-cli",
"version": "0.0.103",
- "description": "Semver-oriented TypeScript library skeleton.",
+ "private": true,
+ "description": "Legacy tarzan/trbl CLI frozen pending the migration decision in issue #1.",
"main": "dist/index.js",
"bin": {
"tarzan": "cli/trbl.sh",
@@ -11,7 +12,7 @@
"typings": "dist/index.d.ts",
"scripts": {
"test": "suman test",
- "postinstall": "./assets/postinstall.sh"
+ "prepublishOnly": "node ./scripts/block-legacy-publish.js"
},
"repository": {
"type": "git",
diff --git a/readme.md b/readme.md
index 1d6991b..1e6e0a7 100755
--- a/readme.md
+++ b/readme.md
@@ -1,51 +1,57 @@
+# Tarzan / tarballs-cli
-#### Tarzan / tarballs-cli
+> **Legacy package — release and installation frozen.** The current shell-dispatched CLI is retained for consumer and behavior discovery, but it is not approved for a new npm or Zed release. npm publication is blocked and the former install-time home-directory write has been removed from `package.json`. See [issue #1](https://github.com/ORESoftware/tarballs-cli/issues/1) and [`docs/migration-decision.md`](docs/migration-decision.md). Do not follow the historical global-install examples below for new systems.
----------------------------------------------------------
+## Historical behavior retained for migration review
-### Clone a git repo, to which you will push files (tarballs, etc).
+### Clone a Git repository to which files were pushed
```bash
-$ tarzan init oresoftware/tarballs "git@github.com:ORESoftware/tarballs.git"
+tarzan init oresoftware/tarballs "git@github.com:ORESoftware/tarballs.git"
```
->
-> the 'init' command clones the git repo to: "$HOME/.trbl/repos/oresoftware/tarballs"
-> and "oresoftware/tarballs" becomes the id for that repo
->
-### Use a repo to push files to
+Historically, `init` cloned the repository under `$HOME/.trbl/repos/oresoftware/tarballs` and registered `oresoftware/tarballs` as its ID. The replacement must validate ownership, paths, symlinks, remotes, credentials, concurrency, and interruption before preserving this behavior.
+
+### Select a repository
```bash
-$ tarzan use oresoftware/tarballs
+tarzan use oresoftware/tarballs
```
->
-> the 'use' command sets a certain repo as the active one (globally/for all shells)
->
-### Add a local file and push it to the remote repo
+Historically, `use` selected one repository globally for all shells. The migration must replace hidden global state with an explicit, validated configuration and must not mutate shell profiles during installation.
+
+### Add and push an artifact
```bash
-$ tarzan add foo.tgz "x/y/z/foo.tgz"
+tarzan add foo.tgz "x/y/z/foo.tgz"
```
->
-> the 'add' command writes a file to the active repo to the path and attempts to push the file to the remote.
->
-----------------------------------------------------
+Historically, `add` copied a file into the active repository and attempted to push it. Any maintained version must default to dry-run, validate paths and remotes, serialize concurrent writers, avoid shell interpolation, prohibit force pushes, and emit bounded redacted receipts.
-### Install a tarball from Github, with NPM, etc
+## Historical raw-GitHub installation example
+
+The previous documentation installed tarballs from mutable branch URLs with a cache-busting query string. This is **not** an approved modern supply-chain workflow:
```bash
+npm install --loglevel=warn -g \
+ "https://raw.githubusercontent.com///master/x/y/z/foo.tgz?$(date +%s)"
+```
-$ npm install --loglevel=warn -g \
- "https://raw.githubusercontent.com///master/x/y/z/foo.tgz?$(date +%s)"
+Do not use this pattern for new builds or Docker images. The migration decision must select an owning package system and use immutable content/revision digests, authenticated provenance, reproducible packaging, and reviewed release receipts.
-```
+## Intended command contract
-### Using a Dockerfile / building a Docker image:
+Root [`.cli-flags.toml`](.cli-flags.toml) declares the ten commands that must be evaluated during migration:
-```bash
-RUN npm install --loglevel=warn -g \
- "https://raw.githubusercontent.com///master/x/y/z/foo.tgz?$(date +%s)"
-```
+- `init`
+- `use`
+- `add`
+- `get`
+- `view`
+- `fetch`
+- `push`
+- `repair`
+- `remove`
+- `remove-all`
+The legacy shell dispatcher does not yet consume the manifest. Issue #1 remains open until flags-2-env is the single parser, retained commands have characterization and adversarial tests, and either a migration or retirement receipt is approved.
diff --git a/scripts/block-legacy-publish.js b/scripts/block-legacy-publish.js
new file mode 100644
index 0000000..dc115fd
--- /dev/null
+++ b/scripts/block-legacy-publish.js
@@ -0,0 +1,10 @@
+'use strict';
+
+const message = [
+ 'tarballs-cli publication is blocked while the legacy CLI is under migration review.',
+ 'See https://github.com/ORESoftware/tarballs-cli/issues/1 for the consumer, parser, packaging, and release gates.',
+ 'Do not bypass this guard or restore install-time side effects in the same change.',
+].join(' ');
+
+process.stderr.write(`${message}\n`);
+process.exitCode = 1;