Skip to content

Commit fc5c9d2

Browse files
1broseidonclaude
andcommitted
refactor: Remove epic/adr types, simplify to tasks-only; add cached tab completion
- Remove task_type parameter from create_task (hardcode "task") - Remove Type display from /task show output - Remove epic/adr/contract/base schema references from docs - Add _get_cached_task_ids with mtime-based cache for tab completion - Fix simplify review issues: stale 'todo' fallback, duplicate session title, redundant find_task after create, hoisted store construction Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent e79afca commit fc5c9d2

5 files changed

Lines changed: 46 additions & 38 deletions

File tree

cecli/brainfile/store.py

Lines changed: 5 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -178,7 +178,6 @@ def create_task(
178178
self,
179179
title: str,
180180
column: str = "in-progress",
181-
task_type: str = "task",
182181
description: Optional[str] = None,
183182
subtasks: Optional[List[str]] = None,
184183
) -> Dict[str, Any]:
@@ -188,7 +187,7 @@ def create_task(
188187
{
189188
"title": title,
190189
"column": column,
191-
"type": task_type,
190+
"type": "task",
192191
"description": description or "",
193192
"subtasks": subtasks or [],
194193
},
@@ -202,10 +201,10 @@ def create_task(
202201
"id": task.id,
203202
"title": task.title,
204203
"column": task.column,
205-
"type": task.type or "task",
206204
"location": "board",
207205
"path": Path(result["filePath"]),
208206
"relpath": self.relpath(result["filePath"]),
207+
"task": task,
209208
}
210209

211210
def update_task(
@@ -351,13 +350,10 @@ def get_or_create_session_task(self, coder) -> dict:
351350
task_id = best["id"]
352351
else:
353352
# Create a new task
354-
from datetime import date
355-
356-
title = f"Session {date.today().isoformat()}"
353+
title = self.auto_title(None)
357354
created = self.create_task(title=title, column="in-progress")
358355
task_id = created["id"]
359-
found = self.find_task(task_id)
360-
task = found["task"]
356+
task = created["task"]
361357

362358
# Set active_task_id + update TUI — but do NOT add the file to
363359
# coder context so the agent never sees raw YAML.
@@ -662,6 +658,6 @@ def render_task_todo_block(self, task_id: str) -> Optional[str]:
662658

663659
total = len(done_tasks) + len(remaining_tasks)
664660
done = len(done_tasks)
665-
result += f"\nActive: {task.title} | {task.column or 'todo'} | {done}/{total}\n"
661+
result += f"\nActive: {task.title} | {task.column or 'in-progress'} | {done}/{total}\n"
666662
result += "</context>"
667663
return result

cecli/coders/agent_coder.py

Lines changed: 9 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1193,30 +1193,23 @@ def get_todo_list(self):
11931193
already exists (to avoid creating one before the agent has done anything).
11941194
"""
11951195
try:
1196+
from cecli.brainfile import CecliTaskStore
1197+
1198+
store = CecliTaskStore(self.root)
11961199
active_task_id = getattr(self, "active_task_id", None)
11971200

11981201
# Auto-resume: pick up an incomplete board task if one exists
1199-
if not active_task_id:
1202+
if not active_task_id and store.board_exists():
12001203
try:
1201-
from cecli.brainfile import CecliTaskStore
1202-
1203-
store = CecliTaskStore(self.root)
1204-
if store.board_exists():
1205-
opened = store.get_or_create_session_task(self)
1206-
active_task_id = opened["id"]
1204+
opened = store.get_or_create_session_task(self)
1205+
active_task_id = opened["id"]
12071206
except Exception:
12081207
pass
12091208

12101209
if active_task_id:
1211-
try:
1212-
from cecli.brainfile import CecliTaskStore
1213-
1214-
store = CecliTaskStore(self.root)
1215-
block = store.render_task_todo_block(active_task_id)
1216-
if block:
1217-
return block
1218-
except Exception:
1219-
pass
1210+
block = store.render_task_todo_block(active_task_id)
1211+
if block:
1212+
return block
12201213

12211214
return (
12221215
'<context name="todo_list" from="agent">\n'

cecli/commands/task.py

Lines changed: 30 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,34 @@ class TaskCommand(BaseCommand):
1414
"(list/add/new/show/open/update/delete/complete/drop)"
1515
)
1616

17+
_cached_task_ids: List[str] = []
18+
_cached_mtime: float = 0.0
19+
20+
@classmethod
21+
def _get_cached_task_ids(cls, coder) -> List[str]:
22+
"""Return task IDs, using a cache invalidated by directory mtime."""
23+
tasks_dir = Path(coder.root) / ".cecli" / "tasks"
24+
board_dir = tasks_dir / "board"
25+
logs_dir = tasks_dir / "logs"
26+
27+
# Sum mtimes of both directories for a cheap staleness check
28+
current_mtime = 0.0
29+
for d in (board_dir, logs_dir):
30+
try:
31+
current_mtime += d.stat().st_mtime
32+
except OSError:
33+
pass
34+
35+
if current_mtime != cls._cached_mtime or not cls._cached_task_ids:
36+
try:
37+
store = CecliTaskStore(Path(coder.root))
38+
cls._cached_task_ids = [t["id"] for t in store.list_tasks("all")]
39+
except Exception:
40+
cls._cached_task_ids = []
41+
cls._cached_mtime = current_mtime
42+
43+
return cls._cached_task_ids
44+
1745
@classmethod
1846
async def execute(cls, io, coder, args, **kwargs):
1947
if coder is None:
@@ -73,7 +101,6 @@ async def execute(cls, io, coder, args, **kwargs):
73101
total = len(subtasks)
74102
io.tool_output(f"Task: {task['id']}")
75103
io.tool_output(f"Title: {t.title}")
76-
io.tool_output(f"Type: {t.type or 'task'}")
77104
io.tool_output(f"Location: {task['location']}")
78105
io.tool_output(f"Column: {t.column or 'logs'}")
79106
io.tool_output(f"Progress: {done}/{total}")
@@ -197,9 +224,7 @@ async def execute(cls, io, coder, args, **kwargs):
197224
if command == "new":
198225
title = " ".join(tokens[1:]).strip() if len(tokens) > 1 else None
199226
if not title:
200-
from datetime import date
201-
202-
title = f"Session {date.today().isoformat()}"
227+
title = store.auto_title(None)
203228
created = store.create_task(title=title, column="in-progress")
204229
opened = store.open_task_in_context(
205230
coder, created["id"], mode="auto", explicit=False
@@ -247,9 +272,6 @@ def get_completions(cls, io, coder, args) -> List[str]:
247272
prefix = tokens[0].lower()
248273
return [sc for sc in subcommands if sc.startswith(prefix)]
249274

250-
store = CecliTaskStore(Path(coder.root))
251-
task_ids = [task["id"] for task in store.list_tasks("all")]
252-
253275
action = tokens[0].lower()
254276
if action == "list":
255277
if len(tokens) <= 1:
@@ -260,6 +282,7 @@ def get_completions(cls, io, coder, args) -> List[str]:
260282
return []
261283

262284
if action in {"show", "open", "update", "delete", "complete", "drop"}:
285+
task_ids = cls._get_cached_task_ids(coder)
263286
if len(tokens) == 1:
264287
return task_ids
265288
if len(tokens) == 2 and not args.endswith(" "):

cecli/sessions.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -249,7 +249,7 @@ def _apply_session_data(self, session_data: Dict, session_file: Path) -> bool:
249249
)
250250
else:
251251
# Task file no longer exists or was completed — clear it
252-
setattr(self.coder, "active_task_id", None)
252+
store.clear_active_task(self.coder)
253253

254254
# Legacy field handling:
255255
# session_data["todo_list"] was used for deprecated todo.txt snapshots.

cecli/website/docs/sessions.md

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -78,13 +78,9 @@ List all available saved sessions in `.cecli/sessions/`.
7878
The persistent board in `.cecli/tasks/` is initialized with Brainfile v2 schema URLs:
7979
8080
- Board: `https://brainfile.md/v2/board.json`
81-
- Base (reference): `https://brainfile.md/v2/base.json`
8281
- Task: `https://brainfile.md/v2/task.json`
83-
- Contract: `https://brainfile.md/v2/contract.json`
84-
- Epic: `https://brainfile.md/v2/epic.json`
85-
- ADR: `https://brainfile.md/v2/adr.json`
8682
87-
The default `types` map includes `task`, `epic`, and `adr` and can be extended later.
83+
Tasks are the only item type used in the initial version.
8884
8985
## How Sessions Work
9086

0 commit comments

Comments
 (0)