Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,16 @@ All notable changes to this project will be documented in this file.
Format follows [Keep a Changelog](https://keepachangelog.com/). This project
adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [0.2.1] - 2026-06-13

### Fixed

- **Console script renamed `tensor` → `tensor-cli`** in `[project.scripts]`. The scaffold bound the executable to `tensor` while the `prog` name, `--help`, explain catalog, tests, and README all used `tensor-cli` — so the installed command didn't match the docs, and the agent-first rubric gate (`teken cli doctor`, which derives the tool name from the first `[project.scripts]` entry) failed `explain_self` (`tensor explain tensor` had no catalog entry). The command is now `tensor-cli` everywhere.

### Changed

- **`/init`: expanded `CLAUDE.md` from the bootstrap seed into a full runtime guide.** Documents that the repo is still the `culture-agent-template` scaffold (no tensor-domain logic yet), the CLI dispatch/`register()` architecture, the `CliError` / stdout-stderr / `--json` contracts, the explain catalog, and the load-bearing agent-first rubric (`teken cli doctor . --strict`). Captures the console-script gotcha (the executable is `tensor`, not `tensor-cli`), the version-bump-every-PR + SonarCloud conventions, the cite-don't-import skill-kit rule, and the clone/rename procedure.

## [0.2.0] - 2026-06-06

### Added
Expand Down
170 changes: 151 additions & 19 deletions CLAUDE.md
Original file line number Diff line number Diff line change
@@ -1,28 +1,160 @@
# CLAUDE.md — seed / bootstrap placeholder
# CLAUDE.md

> **This is a self-initializing seed, not a finished runtime prompt.**
> Run `/init` (or describe the agent's domain to your AI assistant) to
> re-initialize this file into a full runtime prompt, using the description
> below and the scaffolded repo as context.
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
Comment thread
OriNachum marked this conversation as resolved.

## Agent
## What this repo actually is

This repository hosts the **tensor-cli** agent.
`tensor-cli` is a **clonable AgentCulture mesh-agent template**, scaffolded from
`culture-agent-template`. Despite the description "Agent/CLI for tensor
operations and ML tensor manipulation," **no tensor logic exists yet** — the
codebase is the template baseline: an agent-first CLI (the introspection verbs
below), a mesh identity, the vendored skill kit, and CI/deploy wiring. The
tensor domain is the *intended* build, not the current state. Treat domain work
as greenfield; add it as new noun groups (see "Adding a verb or noun" below).

## Description
The runtime package (`tensor/`) has **zero third-party dependencies** — keep it
that way. The CLI is cited (cite-don't-import) from the `teken` `python-cli`
reference; new code should follow the same patterns rather than pull deps.

Agent/CLI for tensor operations and ML tensor manipulation
## Commands

## Re-init instruction
```bash
uv sync # create .venv + install (incl. dev group)
uv run pytest -n auto # full suite (xdist parallel)
uv run pytest tests/test_cli.py::test_whoami_json # a single test
uv run pytest -n auto --cov=tensor --cov-report=term # with coverage (CI gate: 60%)
uv run teken cli doctor . --strict # the agent-first rubric gate CI enforces
```

This file is a seed. To expand it into your full runtime prompt:
Lint (all must pass — CI runs each):

1. Open this repo in Claude Code (or your preferred AI assistant).
2. Run `/init` — the assistant will read the repo, incorporate the description
above, and replace this seed with a complete `CLAUDE.md`.
3. Commit the result.
```bash
uv run black --check tensor tests
uv run isort --check-only tensor tests
uv run flake8 tensor tests
uv run bandit -c pyproject.toml -r tensor
markdownlint-cli2 "**/*.md" "#node_modules" "#.local" "#.claude/skills" "#.teken"
```

Until you run `/init`, `tensor-cli` satisfies the `steward doctor`
`prompt-file-present` and `backend-consistency` invariants (a `CLAUDE.md`
exists and `culture.yaml` declares `backend: claude`) but the prompt is not
yet tailored to this agent's domain.
`markdownlint-cli2` is a Node tool, not part of the uv dev group — install it
separately (CI pins `npm install -g markdownlint-cli2@0.21.0`). The other four
come from `uv sync`.

### Running the CLI

The console command, the distribution name, the argparse `prog`, the explain
catalog keys, and `[project.scripts]` all agree on **`tensor-cli`**:

```bash
uv run tensor-cli whoami # installed console script
uv run python -m tensor whoami # equivalent (module entry point)
```

Note the import package is still `tensor/` (so `python -m tensor`), while the
*command* is `tensor-cli`. The agent-first rubric (`teken cli doctor`) derives
the tool name from the first `[project.scripts]` entry and runs
`<name> explain <name>` against the catalog — so that script name **must** match
a catalog key in `tensor/explain/catalog.py`. If you rename the command, rename
the catalog key (and `prog`) in the same change or the rubric gate fails.

## Architecture

A single argparse tree with a uniform plugin-style registration contract.

- **`tensor/cli/__init__.py`** — `main()` → `_build_parser()` → `_dispatch()`.
Each command module exposes a `register(sub)` that adds its subparser and sets
`func`. To add a command you import it in `_build_parser()` and call
`register(sub)` — nothing else is wired.
- **Error contract (`tensor/cli/_errors.py`)** — every failure raises
`CliError(code, message, remediation)`. `_dispatch()` catches it (and wraps any
stray exception) so **no Python traceback ever reaches stderr**. Argparse
errors are also routed through this: `_CliArgumentParser.error()` overrides the
default `prog: error:` / exit-2 behaviour and emits the structured form with
exit 1. Subparsers inherit it via `parser_class=_CliArgumentParser`.
- **Output contract (`tensor/cli/_output.py`)** — **results to stdout,
errors/diagnostics to stderr, never mixed.** Text errors render as
`error: …\nhint: …` (the `hint:` prefix is required by the agent-first rubric).
`--json` routes structured payloads to the same streams. Every verb takes
`--json`; honour both modes in any new command.
- **Exit codes** — `0` success, `1` user error, `2` environment error, `3+`
reserved. Centralised in `_errors.py`; don't invent ad-hoc codes.
- **`--json` parse-time peek** — JSON-mode errors can fire *before* `args.json`
exists (argparse failures). `main()` pre-scans raw argv and sets
`_CliArgumentParser._json_hint` so even parse errors honour `--json`. Preserve
this if you touch arg parsing.
- **Explain catalog (`tensor/explain/`)** — `tensor/explain/catalog.py` is a
`dict[tuple[str,...], str]` of verbatim markdown keyed by command path;
`resolve()` looks it up or raises `CliError`. Every noun/verb you add should
get a matching catalog entry. Note the coverage gap:
`test_every_catalog_path_resolves` only asserts that the *existing* catalog
keys resolve — it does **not** verify that every registered command has an
entry, so a command added without one won't fail that test. Only the rubric's
`explain_self` (the root command) is enforced in CI; entries for other verbs
are a convention you must uphold by hand.

### The agent-first rubric (load-bearing)

CI gates on `teken cli doctor . --strict`. This is why the introspection verbs
exist and have specific shapes — don't delete them casually:

- `learn` must be ≥200 chars and mention purpose, command map, exit codes,
`--json`, and `explain`.
- Any noun with action-verbs must also expose `overview` (this is the entire
reason the `cli` noun + `cli overview` exist today).
- Descriptive verbs (`overview`) must **never hard-fail on a bad target** —
`overview` accepts and ignores a stray positional path so it always exits 0.
- `doctor` returns the rubric shape `{healthy, checks:[{id,passed,severity,
message,remediation}]}` and mirrors the invariants `steward doctor` checks
(prompt-file-present, backend-consistency) plus a skills-present check.

### Adding a verb or noun

1. Create `tensor/cli/_commands/<name>.py` with `register(sub)` + a
`cmd_<name>(args)->int` handler. Add `--json`; raise `CliError` on failure;
emit via `_output` helpers.
2. Import + `register()` it in `_build_parser()`.
3. Add a `catalog.py` entry for its path(s).
4. If it's a *noun* with action-verbs, give it an `overview` sub-verb (reuse
`overview.py`'s `emit_overview` / section helpers, as `cli.py` does).
5. Add tests under `tests/` (smoke + `--json` shape).

## Identity & the skill kit

- **`culture.yaml`** declares the mesh agent (`suffix: tensor-cli`,
`backend: claude`). `whoami`/`doctor` parse it *without* a YAML dep by walking
up from `__file__` and reading the first agent block — keep the parser tolerant
if you touch `whoami.py`. `backend: claude` requires `CLAUDE.md` to exist
(the backend-consistency invariant).
- **`.claude/skills/`** is vendored **cite-don't-import** from `guildmaster`
(provenance + re-sync procedure in `docs/skill-sources.md`). **Do not edit
vendored script bodies** — only the documented identifier-only adaptations in
`SKILL.md`. To update a skill, re-vendor per `docs/skill-sources.md`. Some
skills need external tools on PATH (`devex`, `agtag`, optionally `colleague`).

## PR / release conventions

- **Every PR bumps the version** — even docs/config/CI. CI (`version-check` job)
blocks merge if `pyproject.toml` version equals `origin/main`. Use the
`version-bump` skill (updates `pyproject.toml` + prepends to `CHANGELOG.md`).
- The `cicd` skill is the PR lane (layered on `devex pr`); `cicd await` polls the
SonarCloud gate + unresolved threads.
- **SonarCloud coverage requires `relative_files = true`** (already set in
`[tool.coverage.run]`) so `coverage.xml` paths match `sonar.sources=tensor`;
absolute paths silently report 0% coverage.
- Publishing is automatic via PyPI Trusted Publishing on push to `main`
(`.github/workflows/publish.yml`); PRs publish a `.devN` build to TestPyPI.

## Renaming the template (when cloning to a real agent)

The name `tensor-cli` / package `tensor/` is hard-coded in ~100 places. Discover
every occurrence first:

```bash
git grep -n 'tensor-cli\|agentculture_tensor-cli\|tensor\b'
```

Then rename: the `tensor/` package dir, `pyproject.toml` (`name`,
`[project.scripts]`, `[tool.hatch...]`, coverage `source`, urls), `tests/`,
`sonar-project.properties` (`projectKey`), all docstrings/prose, and
`culture.yaml` (`suffix`, `backend`). Re-run `/init` afterward and re-vendor only
the skills you need.
4 changes: 2 additions & 2 deletions pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[project]
name = "tensor-cli"
version = "0.2.0"
version = "0.2.1"
description = "Agent/CLI for tensor operations and ML tensor manipulation"
readme = "README.md"
license = "MIT"
Expand All @@ -20,7 +20,7 @@ Homepage = "https://github.com/agentculture/tensor-cli"
Issues = "https://github.com/agentculture/tensor-cli/issues"

[project.scripts]
tensor = "tensor.cli:main"
tensor-cli = "tensor.cli:main"

[build-system]
requires = ["hatchling"]
Expand Down
62 changes: 31 additions & 31 deletions uv.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading