Clu CLI
Architecture
The CLI now follows a layered layout:
src/clu/cli/contains Click command adapters only.src/clu/lib/contains feature orchestration and command entrypoints.src/clu/models/contains flat Pydantic models and enums.src/clu/utils/contains shared pure helpers.src/clu/api/contains backend auth and sync clients.src/clu/store/contains SQLite repositories and the store facade.src/clu/adapter/,src/clu/git.py, andsrc/clu/transcript.pyremain infrastructure-facing modules used by the library layer.
Commands
clu authclu install --global(default is in the current directory)clu append --agent codex/claude/geminiclu flush
Config path: $HOME/.clu/config.toml -- use this to store any secrets, preferences etc.
Happy Path Flow
- User does
clu auth login-- this opens a web based oauth login- After login, the CLI should silently refresh expired access tokens using the stored refresh token.
- User does
clu auth statusto verify the current session and test refresh behavior. - User does
clu installin the project directory, orclu install --globalif they want to install it in the gobal config.- This asks the user what agent to install it for (TUI style picker)
- Installing for claude code modifies the
.claude/settings.jsonand installs theclu appendcommand as the hook for all events and all matches (an example for the settings is added below) - Hooks Reference for Claude: https://code.claude.com/docs/en/hooks#hook-events
- Installing for claude code modifies the
- This asks the user what agent to install it for (TUI style picker)
- The
clu appendcommand reads the hook payload from stdin, stores the raw event locally, and incrementally parses transcript messages into SQLite. - The
clu flushcommand syncs dirty sessions to/sessionsand then bulk-uploads dirty messages to/session-messagesin batches.
Eventual Direction
This SQLite file is the local capture layer. The backend correlates the synced session and message data with GitHub PR events later; the CLI no longer builds or submits a final changeset payload itself.
Settings JSON
{
"hooks": {
"SessionStart": [
{
"matcher": "",
"hooks": [
{
"type": "command",
"command": "/Users/junaidrahim/Code/sandbox/log-hook.sh"
}
]
}
],
"UserPromptSubmit": [
{
"matcher": "",
"hooks": [
{
"type": "command",
"command": "/Users/junaidrahim/Code/sandbox/log-hook.sh"
}
]
}
],
"PreToolUse": [
{
"matcher": "",
"hooks": [
{
"type": "command",
"command": "/Users/junaidrahim/Code/sandbox/log-hook.sh"
}
]
}
],
"PermissionRequest": [
{
"matcher": "",
"hooks": [
{
"type": "command",
"command": "/Users/junaidrahim/Code/sandbox/log-hook.sh"
}
]
}
],
"PermissionDenied": [
{
"matcher": "",
"hooks": [
{
"type": "command",
"command": "/Users/junaidrahim/Code/sandbox/log-hook.sh"
}
]
}
],
"PostToolUse": [
{
"matcher": "",
"hooks": [
{
"type": "command",
"command": "/Users/junaidrahim/Code/sandbox/log-hook.sh"
}
]
}
],
"PostToolUseFailure": [
{
"matcher": "",
"hooks": [
{
"type": "command",
"command": "/Users/junaidrahim/Code/sandbox/log-hook.sh"
}
]
}
],
"Notification": [
{
"matcher": "",
"hooks": [
{
"type": "command",
"command": "/Users/junaidrahim/Code/sandbox/log-hook.sh"
}
]
}
],
"SubagentStart": [
{
"matcher": "",
"hooks": [
{
"type": "command",
"command": "/Users/junaidrahim/Code/sandbox/log-hook.sh"
}
]
}
],
"SubagentStop": [
{
"matcher": "",
"hooks": [
{
"type": "command",
"command": "/Users/junaidrahim/Code/sandbox/log-hook.sh"
}
]
}
],
"TaskCreated": [
{
"matcher": "",
"hooks": [
{
"type": "command",
"command": "/Users/junaidrahim/Code/sandbox/log-hook.sh"
}
]
}
],
"TaskCompleted": [
{
"matcher": "",
"hooks": [
{
"type": "command",
"command": "/Users/junaidrahim/Code/sandbox/log-hook.sh"
}
]
}
],
"Stop": [
{
"matcher": "",
"hooks": [
{
"type": "command",
"command": "/Users/junaidrahim/Code/sandbox/log-hook.sh"
}
]
}
],
"StopFailure": [
{
"matcher": "",
"hooks": [
{
"type": "command",
"command": "/Users/junaidrahim/Code/sandbox/log-hook.sh"
}
]
}
],
"TeammateIdle": [
{
"matcher": "",
"hooks": [
{
"type": "command",
"command": "/Users/junaidrahim/Code/sandbox/log-hook.sh"
}
]
}
],
"InstructionsLoaded": [
{
"matcher": "",
"hooks": [
{
"type": "command",
"command": "/Users/junaidrahim/Code/sandbox/log-hook.sh"
}
]
}
],
"ConfigChange": [
{
"matcher": "",
"hooks": [
{
"type": "command",
"command": "/Users/junaidrahim/Code/sandbox/log-hook.sh"
}
]
}
],
"CwdChanged": [
{
"matcher": "",
"hooks": [
{
"type": "command",
"command": "/Users/junaidrahim/Code/sandbox/log-hook.sh"
}
]
}
],
"FileChanged": [
{
"matcher": "",
"hooks": [
{
"type": "command",
"command": "/Users/junaidrahim/Code/sandbox/log-hook.sh"
}
]
}
],
"WorktreeCreate": [
{
"matcher": "",
"hooks": [
{
"type": "command",
"command": "/Users/junaidrahim/Code/sandbox/log-hook.sh"
}
]
}
],
"WorktreeRemove": [
{
"matcher": "",
"hooks": [
{
"type": "command",
"command": "/Users/junaidrahim/Code/sandbox/log-hook.sh"
}
]
}
],
"PreCompact": [
{
"matcher": "",
"hooks": [
{
"type": "command",
"command": "/Users/junaidrahim/Code/sandbox/log-hook.sh"
}
]
}
],
"PostCompact": [
{
"matcher": "",
"hooks": [
{
"type": "command",
"command": "/Users/junaidrahim/Code/sandbox/log-hook.sh"
}
]
}
],
"Elicitation": [
{
"matcher": "",
"hooks": [
{
"type": "command",
"command": "/Users/junaidrahim/Code/sandbox/log-hook.sh"
}
]
}
],
"ElicitationResult": [
{
"matcher": "",
"hooks": [
{
"type": "command",
"command": "/Users/junaidrahim/Code/sandbox/log-hook.sh"
}
]
}
],
"SessionEnd": [
{
"matcher": "",
"hooks": [
{
"type": "command",
"command": "/Users/junaidrahim/Code/sandbox/log-hook.sh"
}
]
}
]
}
}
Metadata
Release files for clu-cli 1.24.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | |
|---|---|---|---|---|
| clu_cli-1.24.0.tar.gz | 62.6 kB | Without provenance | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| clu_cli-1.24.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 131.1 kB
Release files / clu_cli-1.24.0.tar.gz
| Download URL | clu_cli-1.24.0.tar.gz |
|---|---|
| Size | 62.6 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
f1ce8bae52de8d97bbda65c55e5c46510cd0b8021328edae94c9059be42af22f
|
|
BLAKE2b-256 checksum How to use checksums |
956380b75ce1d89e60a490c8902f478ff0da3ec1859e0339d8d25f37e13222aa
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
uv/0.11.14 {"installer":{"name":"uv","version":"0.11.14","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
|
Release files / clu_cli-1.24.0-py3-none-any.whl
| Download URL | clu_cli-1.24.0-py3-none-any.whl |
|---|---|
| Size | 68.5 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
b8e7f2f173922b41f9209dad89f0d7f2ef57f05f485d094f0036135a077d78ee
|
|
BLAKE2b-256 checksum How to use checksums |
884dfa47e2289030d4230bd3483a2f5f8b2fc19a44e1c37c4b3715d3386ba99a
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
uv/0.11.14 {"installer":{"name":"uv","version":"0.11.14","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
|
Security for clu-cli 1.24.0
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
No provenance found
None of the files in this release were uploaded with provenance metadata.
A note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.