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
52 changes: 49 additions & 3 deletions crates/coven-cli/src/cockpit_sources.rs
Original file line number Diff line number Diff line change
Expand Up @@ -259,10 +259,15 @@ pub fn scan_skills(coven_home: &Path) -> Result<Vec<SkillDto>> {
let mut out = Vec::new();
for entry in entries {
let entry = entry?;
if !entry.file_type()?.is_dir() {
continue;
}
let dir = entry.path();
match fs::metadata(&dir) {
Ok(meta) if meta.is_dir() => {}
Ok(_) => continue,
Err(err) if err.kind() == io::ErrorKind::NotFound => continue,
Err(err) => {
return Err(err).with_context(|| format!("failed to inspect {}", dir.display()));
}
Comment thread
BunsDev marked this conversation as resolved.
}
let metadata_path = dir.join("metadata.json");
let raw = match fs::read_to_string(&metadata_path) {
Ok(raw) => raw,
Expand Down Expand Up @@ -815,6 +820,47 @@ description = "..."
Ok(())
}

#[cfg(unix)]
#[test]
fn scan_skills_follows_symlinked_skill_dirs() -> Result<()> {
let temp = tempfile::tempdir()?;
let canonical = temp.path().join("canonical").join("delta");
fs::create_dir_all(&canonical)?;
fs::write(
canonical.join("metadata.json"),
r#"{"name":"Delta","description":"D","author":"coven","category":"operations"}"#,
)?;

let skills_root = temp.path().join(SKILLS_DIR);
fs::create_dir_all(&skills_root)?;
std::os::unix::fs::symlink(&canonical, skills_root.join("delta"))?;

let out = scan_skills(temp.path())?;

assert_eq!(out.len(), 1);
assert_eq!(out[0].id, "delta");
assert_eq!(out[0].name, "Delta");
assert_eq!(out[0].owner, "coven");
Ok(())
}

#[cfg(unix)]
#[test]
fn scan_skills_skips_dangling_symlinks() -> Result<()> {
let temp = tempfile::tempdir()?;
let skills_root = temp.path().join(SKILLS_DIR);
fs::create_dir_all(&skills_root)?;
std::os::unix::fs::symlink(
temp.path().join("missing-skill"),
skills_root.join("missing-skill"),
)?;

let out = scan_skills(temp.path())?;

assert!(out.is_empty());
Ok(())
}

#[test]
fn scan_memory_returns_empty_when_dir_missing() -> Result<()> {
let temp = tempfile::tempdir()?;
Expand Down
1 change: 1 addition & 0 deletions skills/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ Canonical Coven-wide skills live here. Each skill is a directory with a `SKILL.m
| Skill | Purpose |
|-------|---------|
| `coven-board-entry` | Create a new entry on the Coven task board programmatically |
| `coven-task-manager` | Keep Coven task boards fresh with scheduled stale/blocked/review task hygiene |
| `opencoven-design` | OpenCoven design system and visual language reference |

## Adding a new Coven skill
Expand Down
78 changes: 78 additions & 0 deletions skills/coven-task-manager/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
---
name: coven-task-manager
description: Keep Coven task boards fresh by auditing stale, blocked, active, review, and completed work; use for scheduled task hygiene, task triage, and dynamic task-management runs.
---

# Coven Task Manager

Use this skill when asked to manage, refresh, audit, triage, or summarize Coven tasks, or when a scheduled automation asks for task-board freshness.

## Sources

Start with the Cave task board from the skill directory:

```bash
node ./task-manager.mjs report
```

The helper reads `~/.coven/cave-board.json` and writes `~/.coven/task-manager/freshness-report.md` by default.

If the canonical repo path is different, run the helper from this skill directory:

```bash
node ./task-manager.mjs report --coven-home ~/.coven
```

## Workflow

1. Load the task board and build a freshness report.
2. Inspect the report sections in this order: `Stale Running`, `Needs Human`, `Ready For Review`, then `Next Actions`.
3. Read `Thread Coordination` before touching individual cards. Treat it as the concurrency control surface for simultaneous sessions.
4. For every active/review/blocked thread, build a small ledger: card id/title, familiar, session id, repo/branch/worktree if known, last evidence checked, current state, and one next action.
5. Resolve collisions before dispatching new work:
- If multiple cards share a session, resume that session once and update all linked cards from the same evidence.
- If one familiar has multiple active lanes, choose the primary lane and mark the rest as waiting, review, or blocked with a reason.
- If multiple lanes touch the same repo or branch, verify branch/worktree ownership before allowing parallel writes.
- Prefer resuming a viable linked session over starting a new thread; start a fresh thread only when no current session can be resumed.
6. For each task that needs action, gather concrete evidence before changing state: linked sessions, git branches, PRs, CI, user messages, or task notes.
7. Keep task state fresh:
- Move stale running work only when evidence shows it is blocked, ready for review, done, or abandoned.
- Keep blocked tasks explicit: include the blocker, owner, and smallest next unblock action.
- Move review tasks only after the actual review/CI state is checked.
- Mark work done only when merge, delivery, or acceptance evidence exists.
8. Update the freshness report after meaningful changes.

## Guardrails

- Do not delete, archive, or bulk-close tasks unless the user explicitly asks.
- Do not invent blockers or progress.
- Do not mark a task done from memory alone; verify current state first.
- Preserve user-written task notes. Append concise evidence instead of replacing useful context.
- If evidence is missing, leave the task in place and write the missing check as the next action.
- Do not spawn parallel work for the same repo/branch/session just because several cards look stale; reconcile the existing thread ledger first.

## Default Automations

Install the default Codex automation set with:

```bash
node ./task-manager.mjs install-default-automations --status PAUSED
```

The templates are:

- `coven-task-freshness-daily` — daily sweep of stale, blocked, review, and active work.
- `coven-task-blocked-escalation` — weekday blocked-task escalation.
- `coven-task-weekly-cleanup` — weekly summary and cleanup recommendations.

Use `--status ACTIVE` only when the user wants the automations enabled immediately.

## Local Market Install

To make the skill visible to the local Cave Skills market, symlink it into Coven home:

```bash
node ./task-manager.mjs install-local --status PAUSED
```

The Cave market reads `~/.coven/skills/*/metadata.json` through the Coven daemon.
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
version = 1
id = "coven-task-blocked-escalation"
kind = "cron"
name = "Coven Blocked Task Escalation"
status = "PAUSED"
rrule = "RRULE:FREQ=WEEKLY;BYHOUR=10;BYMINUTE=0;BYDAY=MO,TU,WE,TH,FR"
reasoning_effort = "high"
execution_environment = "worktree"
cwds = []
tags = ["coven", "tasks", "blocked"]
prompt = '''Use the `coven-task-manager` skill to review blocked Coven tasks.

Goals:
- Find blocked cards, cards marked needsHuman, and stale running cards.
- Use Thread Coordination to avoid escalating the same live session or repo collision multiple times.
- Separate real blockers from stale bookkeeping.
- Prepare a short escalation list with owners, evidence, and the smallest next unblock action.
- Do not close, delete, or mark tasks done without concrete evidence.'''
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
version = 1
id = "coven-task-freshness-daily"
kind = "cron"
name = "Coven Task Freshness Daily"
status = "PAUSED"
rrule = "RRULE:FREQ=WEEKLY;BYHOUR=8;BYMINUTE=30;BYDAY=SU,MO,TU,WE,TH,FR,SA"
reasoning_effort = "high"
execution_environment = "worktree"
cwds = []
tags = ["coven", "tasks", "freshness"]
prompt = '''Use the `coven-task-manager` skill to run the daily Coven task freshness sweep.

Goals:
- Load the current Cave task board from the local Coven home.
- Identify stale running tasks, blocked tasks that need human attention, review-ready work, and stale backlog/inbox items.
- Read the Thread Coordination section first and reconcile duplicated sessions, overloaded familiars, and repo/branch collisions before spawning or resuming work.
- Update the task freshness report.
- Only edit task state when there is concrete evidence from the board, linked sessions, git, CI, or explicit user instructions.

Deliverable:
- A concise task freshness summary with next actions and any task cards that need human attention.'''
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
version = 1
id = "coven-task-weekly-cleanup"
kind = "cron"
name = "Coven Weekly Task Cleanup"
status = "PAUSED"
rrule = "RRULE:FREQ=WEEKLY;BYHOUR=17;BYMINUTE=0;BYDAY=FR"
reasoning_effort = "high"
execution_environment = "worktree"
cwds = []
tags = ["coven", "tasks", "cleanup"]
prompt = '''Use the `coven-task-manager` skill for the weekly Coven task-board cleanup.

Goals:
- Summarize done, review, blocked, active, inbox, and backlog cards.
- Summarize simultaneous threads by session, familiar, repo, and branch, then recommend which lanes to resume, park, or merge.
- Detect duplicate or stale cards.
- Suggest archive/delete candidates, but do not perform destructive cleanup unless explicitly approved.
- Update the task freshness report with changes since the last run.'''
13 changes: 13 additions & 0 deletions skills/coven-task-manager/metadata.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
{
"name": "coven-task-manager",
"description": "Comprehensive Coven task-board freshness: audits stale running work, blocked tasks, review queues, active work, and completed-task hygiene.",
"version": "0.1.0",
"author": "OpenCoven Team",
"category": "operations",
"tags": ["tasks", "automation", "freshness", "triage", "cave"],
"defaultAutomations": [
"coven-task-freshness-daily",
"coven-task-blocked-escalation",
"coven-task-weekly-cleanup"
]
}
Loading