Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
d6163e4
feat(platform): add CodeBuddy support with nested slash commands
Mar 22, 2026
3ad9ff7
test(platform): add CodeBuddy test coverage
Mar 22, 2026
09e2f63
docs: add CodeBuddy to supported platforms list and spec guide
Mar 22, 2026
47f1ac6
chore: update docs-site submodule (CodeBuddy platform docs)
Mar 22, 2026
bfd331a
chore: v0.4.0-beta.6 manifest and docs-site changelog
Mar 22, 2026
61f0aaf
0.4.0-beta.6
Mar 22, 2026
9f3bf0f
chore: trellis self update
Mar 22, 2026
9cb4ef7
fix: suppress Pyright import warnings in session-start hooks
Mar 22, 2026
1076cf4
0.4.0-beta.7
Mar 22, 2026
77bb2de
chore: v0.4.0-beta.7 manifest and docs-site changelog
Mar 22, 2026
5d1127b
chore: trellis self update
Mar 22, 2026
9033aec
feat(cli): add branch context to .trellis session and journal records…
Lemonadeccc Mar 23, 2026
efc9b3f
chore: add task PRD for .agents/skills shared layer decoupling
Mar 24, 2026
8293581
feat(codex): add latest codex support (#112)
mcode999 Mar 24, 2026
6503b24
chore: update agents-dir-ownership task PRD and context
Mar 24, 2026
ba75c30
feat(codex): decouple .agents/skills as shared layer, add .codex support
Mar 24, 2026
a99eb19
chore(task): archive 03-24-agents-dir-ownership
Mar 24, 2026
42655a2
chore: record journal
Mar 24, 2026
13b07e9
chore: v0.4.0-beta.8 manifest and docs-site changelog
Mar 24, 2026
1852b99
0.4.0-beta.8
Mar 24, 2026
76c20d0
chore: update docs-site submodule (Codex integration docs)
Mar 24, 2026
7b09e25
chore: update docs-site submodule
Mar 24, 2026
80ceb52
chore: trellis self update
Mar 24, 2026
2682dd1
Merge remote-tracking branch 'origin/main' into feat/v0.4.0-beta
Mar 24, 2026
0dd0122
chore: trellis self update
Mar 24, 2026
c136b8b
docs(marketplace): update trellis-meta skill to v0.4.0-beta.8
Mar 24, 2026
25c5a8b
Merge branch 'main' into feat/v0.4.0-beta
taosu0216 Mar 24, 2026
9ef8429
update skill
Mar 25, 2026
3ebd339
Merge branch 'feat/v0.4.0-beta' of github.com:mindfold-ai/Trellis int…
Mar 25, 2026
8a7a6ca
docs: update docs-site submodule — fix Kilo config docs
Mar 25, 2026
1a00db9
docs: update docs-site submodule — fix all platform docs
Mar 25, 2026
351d8a3
fix(cli): set hasPythonHooks to true for Codex platform
Mar 25, 2026
710d5ea
docs: update docs-site submodule — fix Codex TOML config format
Mar 25, 2026
9e4411c
feat(cli): add Trellis statusLine integration for Claude Code
Mar 26, 2026
21440eb
chore(task): archive 03-26-statusline-integration
Mar 26, 2026
c0f4fce
chore: record journal
Mar 26, 2026
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
182 changes: 182 additions & 0 deletions .claude/hooks/statusline.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,182 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Trellis StatusLine — project-level status display for Claude Code.

Reads Claude Code session JSON from stdin + Trellis task data from filesystem.
Outputs 1-2 lines:
With active task: [P1] Task title (status) + info line
Without task: info line only
Info line: model · ctx% · branch · duration · developer · tasks · rate limits
"""
from __future__ import annotations

import json
import re
import subprocess
import sys
from pathlib import Path


def _read_text(path: Path) -> str:
try:
return path.read_text(encoding="utf-8").strip()
except (FileNotFoundError, PermissionError, OSError):
return ""


def _read_json(path: Path) -> dict:
text = _read_text(path)
if not text:
return {}
try:
return json.loads(text)
except (json.JSONDecodeError, ValueError):
return {}


def _find_trellis_dir() -> Path | None:
"""Walk up from cwd to find .trellis/ directory."""
current = Path.cwd()
for parent in [current, *current.parents]:
candidate = parent / ".trellis"
if candidate.is_dir():
return candidate
return None


def _get_current_task(trellis_dir: Path) -> dict | None:
"""Load current task info. Returns dict with title/status/priority or None."""
task_ref = _read_text(trellis_dir / ".current-task")
if not task_ref:
return None

# Resolve task directory
task_path = Path(task_ref) if Path(task_ref).is_absolute() else trellis_dir.parent / task_ref
task_data = _read_json(task_path / "task.json")
if not task_data:
return None

return {
"title": task_data.get("title") or task_data.get("name") or "unknown",
"status": task_data.get("status", "unknown"),
"priority": task_data.get("priority", "P2"),
}


def _count_active_tasks(trellis_dir: Path) -> int:
"""Count non-archived task directories with valid task.json."""
tasks_dir = trellis_dir / "tasks"
if not tasks_dir.is_dir():
return 0
count = 0
for d in tasks_dir.iterdir():
if d.is_dir() and d.name != "archive" and (d / "task.json").is_file():
count += 1
return count


def _get_developer(trellis_dir: Path) -> str:
content = _read_text(trellis_dir / ".developer")
if not content:
return "unknown"
for line in content.splitlines():
if line.startswith("name="):
return line[5:].strip()
return content.splitlines()[0].strip() or "unknown"


def _get_git_branch() -> str:
try:
result = subprocess.run(
["git", "branch", "--show-current"],
capture_output=True, text=True, timeout=3,
)
return result.stdout.strip() if result.returncode == 0 else ""
except (FileNotFoundError, subprocess.TimeoutExpired):
return ""


def _format_ctx_size(size: int) -> str:
if size >= 1_000_000:
return f"{size // 1_000_000}M"
if size >= 1_000:
return f"{size // 1_000}K"
return str(size)


def _format_duration(ms: int) -> str:
secs = ms // 1000
hours, remainder = divmod(secs, 3600)
mins = remainder // 60
if hours > 0:
return f"{hours}h{mins}m"
return f"{mins}m"


def main() -> None:
# Read Claude Code session JSON from stdin
try:
cc_data = json.loads(sys.stdin.read())
except (json.JSONDecodeError, ValueError):
cc_data = {}

trellis_dir = _find_trellis_dir()
SEP = " \033[90m·\033[0m "

# --- Trellis data ---
task = _get_current_task(trellis_dir) if trellis_dir else None
dev = _get_developer(trellis_dir) if trellis_dir else ""
task_count = _count_active_tasks(trellis_dir) if trellis_dir else 0

# --- CC session data ---
model = cc_data.get("model", {}).get("display_name", "?")
ctx_pct = int(cc_data.get("context_window", {}).get("used_percentage") or 0)
ctx_size = _format_ctx_size(cc_data.get("context_window", {}).get("context_window_size") or 0)
duration = _format_duration(cc_data.get("cost", {}).get("total_duration_ms") or 0)
branch = _get_git_branch()

# Avoid "Opus 4.6 (1M context) (1M)"
if re.search(r"\d+[KMG]\b", model, re.IGNORECASE):
model_label = model
else:
model_label = f"{model} ({ctx_size})"

# Context % with color
if ctx_pct >= 90:
ctx_color = "\033[31m"
elif ctx_pct >= 70:
ctx_color = "\033[33m"
else:
ctx_color = "\033[32m"

# Build info line: model · ctx · branch · duration · dev · tasks [· rate limits]
parts = [
model_label,
f"ctx {ctx_color}{ctx_pct}%\033[0m",
]
if branch:
parts.append(f"\033[35m{branch}\033[0m")
parts.append(duration)
if dev:
parts.append(f"\033[32m{dev}\033[0m")
if task_count:
parts.append(f"{task_count} task(s)")

five_hr = cc_data.get("rate_limits", {}).get("five_hour", {}).get("used_percentage")
if five_hr is not None:
parts.append(f"5h {int(five_hr)}%")
seven_day = cc_data.get("rate_limits", {}).get("seven_day", {}).get("used_percentage")
if seven_day is not None:
parts.append(f"7d {int(seven_day)}%")

info_line = SEP.join(parts)

# Output: task line (only if active) + info line
if task:
print(f"\033[36m[{task['priority']}]\033[0m {task['title']} \033[33m({task['status']})\033[0m")
print(info_line)


if __name__ == "__main__":
main()
4 changes: 4 additions & 0 deletions .claude/settings.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
{
"statusLine": {
"type": "command",
"command": "python3 .claude/hooks/statusline.py"
},
"hooks": {
"SessionStart": [
{
Expand Down
2 changes: 1 addition & 1 deletion .codex/config.toml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# Project-scoped Codex defaults for Trellis workflows.
# Codex loads this after ~/.codex/config.toml when you work in this repository.
# Codex loads this after ~/.codex/config.toml when you work in this project.

# Keep AGENTS.md as the primary project instruction file.
project_doc_fallback_filenames = ["AGENTS.md"]
3 changes: 2 additions & 1 deletion .trellis/.template-hashes.json
Original file line number Diff line number Diff line change
Expand Up @@ -77,5 +77,6 @@
".agents/skills/onboard/SKILL.md": "ec6db142f763c81a3273be45b5d7726f695c32aaa5404e90dbd6e40aec92fb98",
".agents/skills/record-session/SKILL.md": "2f3781d894b7a45b517d36845fa18e6fac98acad40e77438a3d85760f1d7d247",
".agents/skills/start/SKILL.md": "8853e4ddc1681e043dec34be76c7c6fd961a3d52cbd0a2320225d72440425639",
".agents/skills/update-spec/SKILL.md": "7ccf7d29ea26d28b0bd8af94ea5b8bfcddaddd9f2797f3becedbe5f3a0a9e9a7"
".agents/skills/update-spec/SKILL.md": "7ccf7d29ea26d28b0bd8af94ea5b8bfcddaddd9f2797f3becedbe5f3a0a9e9a7",
".codex/config.toml": "7543da7e1773a0f26bc9178716b34154fdc5fefd820fb184e7cb169f1910cc99"
}
2 changes: 1 addition & 1 deletion .trellis/.version
Original file line number Diff line number Diff line change
@@ -1 +1 @@
0.4.0-beta.7
0.4.0-beta.8
35 changes: 35 additions & 0 deletions .trellis/tasks/03-24-py39-compat/prd.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
# fix: Python 3.9 compatibility — add future annotations

## Goal

Fix Python 3.9 compatibility issue (#113). Trellis Python scripts use `X | Y` union type syntax (PEP 604, Python 3.10+), causing runtime errors on Python 3.9.

## Requirements

- Add `from __future__ import annotations` to all 21 affected Python files in `.trellis/scripts/`
- Add the same to all corresponding template copies in `packages/cli/src/templates/trellis/scripts/`
- Verify both copies remain identical after changes
- Consider adding Python version check during `trellis init`

## Affected Files (21)

- add_session.py
- common/cli_adapter.py, config.py, developer.py, git.py, io.py
- common/packages_context.py, paths.py, registry.py, session_context.py
- common/task_context.py, task_queue.py, task_store.py, task_utils.py, tasks.py, types.py, worktree.py
- hooks/linear_sync.py
- multi_agent/create_pr.py, status_display.py, status_monitor.py

## Acceptance Criteria

- [ ] All scripts work on Python 3.9+
- [ ] `from __future__ import annotations` added to all affected files
- [ ] Template copies identical to live scripts
- [ ] `pnpm test` passes
- [ ] No `tuple[...]` runtime usage (only in annotations)

## Technical Notes

- `from __future__ import annotations` makes all annotations strings (PEP 563), so `X | Y` works on 3.9
- Must check for runtime type usage like `isinstance(x, str | int)` — those need `Union[str, int]` instead
- GitHub issue: #113
47 changes: 47 additions & 0 deletions .trellis/tasks/03-24-py39-compat/task.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
{
"id": "py39-compat",
"name": "py39-compat",
"title": "fix: Python 3.9 compatibility — add future annotations",
"description": "",
"status": "planning",
"dev_type": null,
"scope": null,
"package": "cli",
"priority": "P2",
"creator": "taosu",
"assignee": "taosu",
"createdAt": "2026-03-24",
"completedAt": null,
"branch": null,
"base_branch": "feat/v0.4.0-beta",
"worktree_path": null,
"current_phase": 0,
"next_action": [
{
"phase": 1,
"action": "implement"
},
{
"phase": 2,
"action": "check"
},
{
"phase": 3,
"action": "finish"
},
{
"phase": 4,
"action": "create-pr"
}
],
"commit": null,
"pr_url": null,
"subtasks": [],
"children": [],
"parent": null,
"relatedFiles": [],
"notes": "",
"meta": {
"linear_issue": "MIN-415"
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
{
"id": "statusline-integration",
"name": "statusline-integration",
"title": "StatusLine: 集成 Trellis 任务状态到 Claude Code 状态栏",
"description": "",
"status": "completed",
"dev_type": null,
"scope": null,
"package": "cli",
"priority": "P2",
"creator": "taosu",
"assignee": "taosu",
"createdAt": "2026-03-26",
"completedAt": "2026-03-26",
"branch": null,
"base_branch": "feat/v0.4.0-beta",
"worktree_path": null,
"current_phase": 0,
"next_action": [
{
"phase": 1,
"action": "implement"
},
{
"phase": 2,
"action": "check"
},
{
"phase": 3,
"action": "finish"
},
{
"phase": 4,
"action": "create-pr"
}
],
"commit": null,
"pr_url": null,
"subtasks": [],
"children": [],
"parent": null,
"relatedFiles": [],
"notes": "",
"meta": {
"linear_issue": "MIN-416"
}
}
7 changes: 4 additions & 3 deletions .trellis/workspace/taosu/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@

<!-- @@@auto:current-status -->
- **Active File**: `journal-4.md`
- **Total Sessions**: 104
- **Last Active**: 2026-03-24
- **Total Sessions**: 105
- **Last Active**: 2026-03-26
<!-- @@@/auto:current-status -->

---
Expand All @@ -19,7 +19,7 @@
<!-- @@@auto:active-documents -->
| File | Lines | Status |
|------|-------|--------|
| `journal-4.md` | ~153 | Active |
| `journal-4.md` | ~187 | Active |
| `journal-3.md` | ~1988 | Archived |
| `journal-2.md` | ~1963 | Archived |
| `journal-1.md` | ~1998 | Archived |
Expand All @@ -32,6 +32,7 @@
<!-- @@@auto:session-history -->
| # | Date | Title | Commits | Branch |
|---|------|-------|---------|--------|
| 105 | 2026-03-26 | StatusLine: 集成 Trellis 任务状态到 CC 状态栏 | `9e4411c` | `feat/v0.4.0-beta` |
| 104 | 2026-03-24 | Decouple .agents/skills as shared layer + Codex .codex support | `ba75c30` | `feat/v0.4.0-beta` |
| 103 | 2026-03-16 | Rename empty templates to from scratch | `57a243d` |
| 102 | 2026-03-13 | Publish-Skill Command & Docs-Site Sync | `d8d7dfb`, `b93ef30` |
Expand Down
Loading
Loading