Skip to content

Add task-memory skill and heartbeat suppression#2

Open
latentloop07 wants to merge 2 commits into
TinyAGI:mainfrom
latentloop07:main
Open

Add task-memory skill and heartbeat suppression#2
latentloop07 wants to merge 2 commits into
TinyAGI:mainfrom
latentloop07:main

Conversation

@latentloop07
Copy link
Copy Markdown

@latentloop07 latentloop07 commented Feb 9, 2026

PR Summary

Feature 1: Persistent Task Memory (00d2303)

Added a task-memory skill that gives TinyClaw persistent task tracking via Claude Code's native skills system.

How it works

  • Claude auto-detects task intent from natural language ("remind me", "todo", "don't forget")
  • Creates individual markdown files with YAML frontmatter in .tinyclaw/tasks/active/
  • Maintains a lightweight index.json for quick scanning
  • Supports recurring tasks, dependencies (blocked_by), and priority levels
  • Completed/cancelled tasks move to .tinyclaw/tasks/completed/

Heartbeat integration

  • Updated .tinyclaw/heartbeat.md with a smart checklist — checks overdue, due-today, due-within-1-hour tasks
  • Added HEARTBEAT_OK suppression in queue-processor — when nothing is due, the heartbeat response is silently discarded instead of being written to the outgoing queue

Files added

File Purpose
.claude/skills/task-memory/SKILL.md Core skill instructions
.claude/skills/task-memory/templates/task-template.md YAML frontmatter template for new tasks
.claude/skills/task-memory/examples/sample-tasks.md Few-shot examples (explicit, implicit, recurring, dependencies)
docs/plans/2026-02-09-persistent-memory-task-tracking-design.md Design doc

Feature 2: TypeScript Migration (a1de864)

Migrated the codebase from JavaScript to TypeScript with strict mode.

New structure

src/
  types.ts              — shared interfaces (QueueMessage, ResponseMessage, TaskIndexEntry)
  queue-processor.ts    — converted from queue-processor.js
  whatsapp-client.ts    — converted from whatsapp-client.js
tsconfig.json           — src/ → dist/, strict, sourceMaps, declarations
dist/                   — compiled output (gitignored)

What changed

  • Both .js files moved to src/ as .ts with full type annotations
  • Shared types.ts defines the queue message protocol as interfaces
  • tsconfig.json compiles src/dist/ with strict mode, source maps, and declaration files
  • package.json updated with build / build:watch scripts, added typescript, @types/node, @types/qrcode-terminal as devDeps
  • tinyclaw.sh now runs node dist/*.js and auto-builds TypeScript if source files are newer than compiled output
  • .gitignore updated to exclude dist/

Key design decision

Zero runtime dependencies added — TypeScript is a devDependency only. Production runs compiled JS via node dist/.

Introduce a task-memory skill and supporting artifacts for persistent task tracking: add .claude/skills/task-memory (SKILL.md, template, examples) and a design doc under docs/plans. Update .tinyclaw/heartbeat.md with a checklist-driven heartbeat behavior and add .tinyclaw/tasks/ to .gitignore. Modify queue-processor.js to suppress HEARTBEAT_OK responses for heartbeat channel (skip writing to outgoing queue and remove the processing file) to avoid sending empty heartbeat messages.
Rename/convert core JS modules to TypeScript (whatsapp-client.js -> src/whatsapp-client.ts, queue-processor.js -> src/queue-processor.ts), add src/types.ts and tsconfig.json. Update package.json and add package-lock.json, update .gitignore to exclude build output (dist/) and keep existing runtime ignores, and apply a minor update to tinyclaw.sh.
@jlia0
Copy link
Copy Markdown
Collaborator

jlia0 commented Feb 11, 2026

This is a very cool skill to add, would you mind explaining a little bit on how would we benefit from task-skill? Is it more like scheduling task with cron jobs?

@latentloop07
Copy link
Copy Markdown
Author

thanks! @jlia0 its similar idea to cron but way more flexible

The core advantage is everything stays natural language end to end. you just talk to it normally and it figures out what to track:

  • "remind me every friday to review open PRs" (sets up recurring)
  • "after the tests pass, deploy to staging" (understands dependencies)
  • "push the groceries thing to next week" (reschedules naturally)
  • "whats overdue?" (queries the task list)

With cron these are all separate problems you need to define upfront. here the behaviour is just prompt instructions that claude interprets at runtime, so it adapts to whatever you throw at it without any predefined rules

The other thing is cron is fire and forget, it doesnt understand context. this skill reads the full task state every 5 min and makes judgement calls, like nudging you about a task. Thats been sitting for a week with no due date, or not bothering you about low priority stuff when theres urgent things pending. that kind of situational awareness is hard to get with static scheduling.

This is a very cool skill to add, would you mind explaining a little bit on how would we benefit from task-skill? Is it more like scheduling task with cron jobs?

@dagelf
Copy link
Copy Markdown

dagelf commented Feb 16, 2026

Can't you do this with the existing heartbeat.md?

edit: I see it's just a more elaborate version of that.

@dagelf
Copy link
Copy Markdown

dagelf commented Feb 16, 2026

Would be great if it's skills for tinyclaw and not just for claude

malloryatefa added a commit to malloryatefa/tinyclaw that referenced this pull request Feb 16, 2026
Fix TinyAGI#1 (High): Port config now respects settings.json. Only MSTEAMS_PORT
env var overrides config; the generic PORT env var and default 3978 no
longer shadow channels.teams.port from settings.

Fix TinyAGI#2 (High): Proactive messaging works via senderId fallback. Stores
conversation references by senderId on every incoming message. Outgoing
queue falls back to senderReferences when pendingMessages has no match,
matching the pattern used by Telegram/Discord/WhatsApp clients.

Fix TinyAGI#3 (High): Real file download/upload support. Incoming attachments
are downloaded to ~/.tinyclaw/files/ with [file: /path] references in
queue messages. Outgoing files are sent as base64-encoded attachments
via the Bot Framework activity API.

Fix TinyAGI#4 (Medium): /reset command implemented. Handles both bare /reset
(shows usage) and /reset @agent_id (writes reset_flag), matching the
exact pattern from telegram-client.ts.

Fix TinyAGI#5 (Medium): Empty message guard added. responseText.trim() is
checked before calling splitMessage/sendActivity in the outgoing queue,
preventing empty activity sends for file-only responses.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@jlia0 jlia0 removed this from TinyAGI Roadmap Mar 1, 2026
dpbmaverick98 pushed a commit to dpbmaverick98/tinyclaw that referenced this pull request Mar 5, 2026
…documentation

**What**
Fixed two issues in recoverStaleConversations():
1. Don't update updated_at when marking as completed (keeps original timestamp)
2. Enhanced documentation explaining why team_chain_end is NOT emitted

**Why Issue TinyAGI#1: Pruning Timestamp Reset**

Previous code:
```typescript
UPDATE conversations
SET status = 'completed', updated_at = ?  ← WRONG: resets timestamp
WHERE status = 'active' AND updated_at < ?
```

Problem timeline:
- T=0: Conversation starts, updated_at = T0
- T=30min: Conversation gets stuck (no updates)
- T=30min: Recovery runs, marks completed, sets updated_at = T30
- T=30min+24h: pruneOldConversations() looks for updated_at < 24h ago
- Result: Conversation not pruned until T=30min+24h (stays in DB 24+ hours)

Better approach:
```typescript
UPDATE conversations
SET status = 'completed'  ← Keep original updated_at timestamp
WHERE status = 'active' AND updated_at < ?
```

Now pruning works correctly:
- Stale conversation marked completed at T=30min
- Original updated_at = T0 (30+ min ago)
- pruneOldConversations() deletes it when updated_at < 24h ago (works!)

**Why Issue TinyAGI#2: Missing team_chain_end Event**

Recovery completion is NOT a natural completion:
- Natural completion: All agents finish, responses aggregated, user gets result
- Stale recovery: Conversation abandoned after crash, responses may be incomplete

Implications:
- Visualizer won't show recovery as "completed" (correct - it's artificial)
- Events not sent (prevents false positives in monitoring)
- Users understand recovery = lost work, not success

Alternative considered: Emit team_chain_end with recovery flag
- Rejected: Would confuse visualizer and monitoring
- Recovery should be silent cleanup, not broadcast as completion

**Assumptions**
1. Keeping original updated_at is correct behavior (allows proper pruning)
2. Silent recovery is acceptable (users can retry if needed)
3. 30-minute stale threshold correctly identifies stuck conversations
4. Not emitting events prevents false positives in event-based systems

**Testing**
Verify:
1. Stale conversation marked as completed
2. completed_at timestamp NOT changed (still ~30min old)
3. pruneOldConversations() deletes it after 24h from original time
4. No team_chain_end event in logs for recovered conversations

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
dpbmaverick98 referenced this pull request in dpbmaverick98/tinyclaw Mar 5, 2026
What:
- Import getPendingRequestsForConversation from db.ts
- In handleTeamResponse, check if agent's response completes an outstanding request
- If matching request found (same conversation, agent was target, status=acked),
  call respondToRequest to mark it complete

Why:
The request-reply pattern requires the response to be tracked. Previously we:
1. Created request when agent A mentioned agent B
2. Acknowledged when agent B received
3. But never marked complete when agent B responded

This meant requests would stay in 'acked' state forever, eventually escalating
even though the agent actually responded.

Now when agent B responds, we find the matching request and mark it complete.

Assumptions:
- Agent responds within the same conversation
- Only one pending request per agent per conversation (find() returns first)
- Response content is stored in the request record for audit

Risk: Low - additive check, doesn't change response handling
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants