ChatTea CLI Alignment Plan
This document defines ChatTea's evidence-bound CLI direction for ChatArch Gitea.
The goal is not to clone GitHub CLI. ChatTea is a Gitea CLI and local Gitea operator tool. Command names may follow familiar GitHub/Gitea resource concepts when they match Gitea's real API, but every command must be backed by a real Gitea REST route or by an explicitly designed ChatTea local capability.
Evidence Policy
A command may enter the official CLI tree only when at least one of these is true:
- A Gitea REST route exists in
core/gitea/routers/api/v1/**Swagger annotations. - The command is a ChatTea local capability with a concrete implementation contract, such as
set-token,server, orrepo clone.
Do not add placeholder commands. Do not add a command only because GitHub CLI has it. If Gitea does not support the capability, keep it out of the tree until there is a real local design or a real Gitea route.
Implementation Contract
Every CLI command must be a thin adapter over importable Python code.
For each public command, implementation must include:
- A reusable Python function or method that can be called without invoking the CLI.
- A CLI wrapper that only parses options, resolves interactive input, calls the Python function, and renders output.
- A test for the reusable Python function or API method.
- A CLI smoke/behavior test for command registration, argument parsing, output, and failure mode.
- Documentation that maps the command to either a Gitea REST route or a ChatTea local function.
The CLI must not be the only stable integration surface. Python integrations, MCP tools, and future gateway adapters should call Python functions directly instead of shelling out to chattea ....
Preferred shape:
src/chattea/
├── api.py or api/<domain>.py # Gitea REST client methods; no Click rendering.
├── credentials.py # set-token, token resolution, repo-local git credential helpers.
├── server.py # local Gitea install/service/config primitives.
└── commands/
├── token.py # Click command group + thin wrappers around token functions.
├── repo.py # Click command group + thin wrappers around repo functions.
├── issue.py # Click command group + thin wrappers around issue functions.
├── pr.py # Click command group + thin wrappers around pull request functions.
├── project.py # Click command group + thin wrappers around project/card functions.
└── ...
This layout should follow the CLI tree when practical. It can stay flexible when a shared lower-level class or helper is clearer, but domain logic must remain importable and decoupled from Click.
Token And Credential Contract
set-token is not a simple clone of auth login and not just a dotenv writer.
set-token is ChatTea's credential foundation:
- Configure token access for the current repository/Gitea remote so git transport can pull and push without repeatedly asking for a token.
- Save or update the ChatTea/ChatEnv token profile when appropriate.
- Provide the token source used by API commands such as
repo,issue,pr,project,release, and Actions commands. - Keep raw tokens out of normal command output.
Token resolution for API commands is centralized and consistent:
- Explicit CLI token argument, when provided.
- Repo-local git credential/config derived from the current Gitea remote, when available.
- ChatTea ChatEnv profile token.
- Clean failure if the command requires authentication and no token is available.
Token creation is separate from token configuration:
token createuses Gitea BasicAuth againstPOST /users/{username}/tokensto create an access token.token bootstrapcreates an access token and immediately calls the same credential configuration path asset-token.set-tokenconfigures an already-created token for ChatTea and git transport.
Confirmed Current ChatTea CLI
This is the currently implemented surface on the working branch. It is not the complete target.
chattea
├── set-token # `chattea.commands.auth.configure_token` -> ChatEnv + repo-local git extraHeader credential.
├── api # Raw Gitea API passthrough via `chattea.commands.api.call_api`.
├── auth # Auxiliary status/login namespace; uses the same credential backend as set-token.
│ ├── login # Configure Gitea API + repo-local git credentials.
│ ├── status # Show configured base URL and masked token state.
│ └── token # Show masked configured token.
├── token # Gitea access token lifecycle through BasicAuth.
│ ├── create # POST /users/{username}/tokens -> `create_access_token`.
│ ├── list # GET /users/{username}/tokens -> `list_access_tokens`.
│ ├── delete # DELETE /users/{username}/tokens/{token} -> `delete_access_token`.
│ └── bootstrap # create token + configure ChatTea/Git credentials.
├── server # Local/internal Gitea lifecycle management.
│ ├── install # `chattea.commands.server.install_gitea` -> `chattea.server.install_binary`.
│ ├── init # `chattea.commands.server.init_gitea_server`.
│ ├── bootstrap # local install/init/admin/token/credential workflow via `bootstrap_gitea_server`.
│ ├── serve # `chattea.commands.server.serve_gitea`.
│ ├── start # `chattea.commands.server.start_gitea_service`.
│ ├── stop # `chattea.commands.server.stop_gitea_service`.
│ ├── restart # `chattea.commands.server.restart_gitea_service`.
│ ├── status # `chattea.commands.server.status_gitea_service`.
│ ├── logs # `chattea.commands.server.logs_gitea_service`.
│ ├── version # `chattea.commands.server.gitea_version`.
│ ├── health # `chattea.commands.server.check_gitea_health`.
│ └── config # Local app.ini helpers.
│ ├── path # `resolve_gitea_config_path`.
│ ├── show # `read_gitea_config`.
│ ├── get # `get_gitea_config_value`.
│ └── set # `set_gitea_config_value`.
├── repo # Repository operations.
│ ├── list # Gitea API-backed `list_repositories`.
│ ├── view # Gitea API-backed `view_repository`.
│ ├── create # Gitea API-backed `create_repository`.
│ ├── clone # Local git helper `clone_repository`.
│ └── migrate # Gitea API-backed `migrate_repository`.
├── issue # Repository issue operations; backed by /repos/{owner}/{repo}/issues.
│ ├── list # GET /repos/{owner}/{repo}/issues.
│ ├── view # GET /repos/{owner}/{repo}/issues/{index}.
│ ├── create # POST /repos/{owner}/{repo}/issues.
│ ├── edit # PATCH /repos/{owner}/{repo}/issues/{index}.
│ ├── close # PATCH issue state=closed.
│ ├── reopen # PATCH issue state=open.
│ ├── delete # DELETE /repos/{owner}/{repo}/issues/{index}.
│ ├── comment # Issue comment API.
│ ├── label # Issue label assignment API.
│ └── assign # Issue assignee API.
├── label # Repository labels.
│ ├── list # GET /repos/{owner}/{repo}/labels.
│ ├── view # GET /repos/{owner}/{repo}/labels/{id}.
│ ├── create # POST /repos/{owner}/{repo}/labels.
│ ├── edit # PATCH /repos/{owner}/{repo}/labels/{id}.
│ └── delete # DELETE /repos/{owner}/{repo}/labels/{id}.
├── milestone # Repository milestones.
│ ├── list # GET /repos/{owner}/{repo}/milestones.
│ ├── view # GET /repos/{owner}/{repo}/milestones/{id}.
│ ├── create # POST /repos/{owner}/{repo}/milestones.
│ ├── edit # PATCH /repos/{owner}/{repo}/milestones/{id}.
│ ├── close # PATCH milestone state=closed.
│ └── delete # DELETE /repos/{owner}/{repo}/milestones/{id}.
├── pr # Pull request operations; no local checkout helper in this tree.
│ ├── list # GET /repos/{owner}/{repo}/pulls.
│ ├── view # GET /repos/{owner}/{repo}/pulls/{index}.
│ ├── create # POST /repos/{owner}/{repo}/pulls.
│ ├── edit # PATCH /repos/{owner}/{repo}/pulls/{index}.
│ ├── close # PATCH PR state=closed.
│ ├── reopen # PATCH PR state=open.
│ ├── merge # POST /repos/{owner}/{repo}/pulls/{index}/merge.
│ ├── diff # GET /repos/{owner}/{repo}/pulls/{index}.diff.
│ ├── patch # GET /repos/{owner}/{repo}/pulls/{index}.patch.
│ ├── commits # GET /repos/{owner}/{repo}/pulls/{index}/commits.
│ ├── files # GET /repos/{owner}/{repo}/pulls/{index}/files.
│ ├── comment # PR issue-comment helpers through issue comment routes.
│ └── review # PR review list/create/submit routes.
├── release # Repository releases.
│ ├── list # GET /repos/{owner}/{repo}/releases.
│ ├── view # GET /repos/{owner}/{repo}/releases/{id}.
│ ├── latest # GET /repos/{owner}/{repo}/releases/latest.
│ ├── by-tag # GET /repos/{owner}/{repo}/releases/tags/{tag}.
│ ├── create # POST /repos/{owner}/{repo}/releases.
│ ├── edit # PATCH /repos/{owner}/{repo}/releases/{id}.
│ ├── delete # DELETE /repos/{owner}/{repo}/releases/{id}.
│ └── asset # Release asset list/delete; upload awaits multipart client support.
└── project # Repository-scoped Gitea Project board, not GitHub Projects v2.
├── list # GET /repos/{owner}/{repo}/projects.
├── view # GET /repos/{owner}/{repo}/projects/{id}.
├── create # POST /repos/{owner}/{repo}/projects.
├── edit # PATCH /repos/{owner}/{repo}/projects/{id}.
├── delete # DELETE /repos/{owner}/{repo}/projects/{id}.
├── column # Repository Project column API.
│ ├── list # GET /repos/{owner}/{repo}/projects/{id}/columns.
│ ├── create # POST /repos/{owner}/{repo}/projects/{id}/columns.
│ ├── edit # PATCH /repos/{owner}/{repo}/projects/{id}/columns/{column_id}.
│ └── delete # DELETE /repos/{owner}/{repo}/projects/{id}/columns/{column_id}.
└── card # Project card API; REST path calls these `issues`.
├── list # GET /repos/{owner}/{repo}/projects/{id}/columns/{column_id}/issues.
├── add # POST /repos/{owner}/{repo}/projects/{id}/columns/{column_id}/issues/{issue_id}.
├── remove # DELETE /repos/{owner}/{repo}/projects/{id}/columns/{column_id}/issues/{issue_id}.
└── move # POST /repos/{owner}/{repo}/projects/{id}/issues/{issue_id}/move.
Compatibility aliases such as project issue may exist for transition, but they are not the official target surface. New docs and automation should use project card.
Confirmed API Domains For Full Implementation
The following domains are confirmed from Gitea Swagger annotations in core/gitea/routers/api/v1/** and can be implemented as real commands. Each command added under these domains must still follow the implementation contract above.
user: admin user creation/edit/delete routes under/admin/users; used for managed local bootstrap.token:/users/{username}/tokenslist/create/delete; create requires BasicAuth or reverse proxy auth.issue:/repos/{owner}/{repo}/issues, comments, labels, reactions, pin/lock, dependencies, attachments, time tracking.label:/repos/{owner}/{repo}/labelsand optional org label routes.milestone:/repos/{owner}/{repo}/milestones.pr:/repos/{owner}/{repo}/pulls, diff/patch, files, commits, merge, update, reviews, requested reviewers.release:/repos/{owner}/{repo}/releasesand release assets.runner/run/job/artifact: Gitea Actions MVP surface for runner registration/lifecycle and PR-triggered run/job/log/artifact inspection. API-backed commands map to/repos/{owner}/{repo}/actions/...;runner setupcommands are local system helpers that install/register/start agitea-runnerprocess.project: repository-scoped/repos/{owner}/{repo}/projectsonly; not GitHub Projects v2.workflow:/repos/{owner}/{repo}/actions/workflows.run:/repos/{owner}/{repo}/actions/runs.job:/repos/{owner}/{repo}/actions/jobs.artifact:/repos/{owner}/{repo}/actions/artifacts.runner: repo/org/user/admin scoped/actions/runnersroutes.secret: repo/org/user scoped/actions/secretsroutes, noting user scope lacks a list route in the observed annotations.variable: repo/org/user scoped/actions/variablesroutes.status:/repos/{owner}/{repo}/statuses/{sha}and combined status routes.
Bootstrap Direction
Initial configuration should be implemented as real workflow composition, not a placeholder command.
server bootstrapor top-levelbootstrapis a local managed-Gitea flow: install, init, start, create default user, generate/create token, run set-token, and verify/user.token bootstrapis the remote/existing-Gitea flow: BasicAuth create token, run set-token, and verify/user.- Passwords should be read from prompt or
--password-env; raw passwords should not be stored in ChatEnv or printed. - Generated access tokens should be saved through the credential path, then masked in normal output.
Non-Goals
- Do not claim full GitHub API or GitHub CLI compatibility.
- Do not model Gitea repository Project boards as GitHub Projects v2.
- Do not add
checkoutto the formal REST-backed tree. If needed later, design it explicitly as a local git helper with its own evidence and tests. - Do not add runner lifecycle commands such as
runner install/start/stop/logsuntil there is a real local runner lifecycle design. - Do not put business logic only in Click command bodies.
- Do not make repository/project/issue/runner IDs ChatEnv fields; they are request parameters.
Test And CI Contract
Each implemented domain should have these gates:
- Unit tests for API path, method, payload, token resolution, and error handling.
- Direct Python function tests for non-trivial command behavior.
- CLI smoke tests for help, success, and expected failures.
- Integration smoke where feasible against a local ChatArch Gitea instance, using task-local state and temporary repos/projects/issues.
pytest, package build,twine check,mkdocs build --strict, andgit diff --checkbefore PR readiness.