Add task-memory skill and heartbeat suppression#2
Conversation
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.
|
This is a very cool skill to add, would you mind explaining a little bit on how would we benefit from |
|
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:
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.
|
|
Can't you do this with the existing heartbeat.md? edit: I see it's just a more elaborate version of that. |
|
Would be great if it's skills for tinyclaw and not just for claude |
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>
…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>
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
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
.tinyclaw/tasks/active/index.jsonfor quick scanningblocked_by), and priority levels.tinyclaw/tasks/completed/Heartbeat integration
.tinyclaw/heartbeat.mdwith a smart checklist — checks overdue, due-today, due-within-1-hour tasksHEARTBEAT_OKsuppression inqueue-processor— when nothing is due, the heartbeat response is silently discarded instead of being written to the outgoing queueFiles added
.claude/skills/task-memory/SKILL.md.claude/skills/task-memory/templates/task-template.md.claude/skills/task-memory/examples/sample-tasks.mddocs/plans/2026-02-09-persistent-memory-task-tracking-design.mdFeature 2: TypeScript Migration (a1de864)
Migrated the codebase from JavaScript to TypeScript with strict mode.
New structure
What changed
.jsfiles moved tosrc/as.tswith full type annotationstypes.tsdefines the queue message protocol as interfacestsconfig.jsoncompilessrc/→dist/with strict mode, source maps, and declaration filespackage.jsonupdated withbuild/build:watchscripts, addedtypescript,@types/node,@types/qrcode-terminalas devDepstinyclaw.shnow runsnode dist/*.jsand auto-builds TypeScript if source files are newer than compiled output.gitignoreupdated to excludedist/Key design decision
Zero runtime dependencies added — TypeScript is a devDependency only. Production runs compiled JS via
node dist/.