Skip to content

feat(todo): add agent tools for todo lists, remove notes_set_done - #2035

Open
hognek wants to merge 12 commits into
jaylfc:devfrom
hognek:feat/1923-notes-todo-agent-tools
Open

feat(todo): add agent tools for todo lists, remove notes_set_done#2035
hognek wants to merge 12 commits into
jaylfc:devfrom
hognek:feat/1923-notes-todo-agent-tools

Conversation

@hognek

@hognek hognek commented Jul 19, 2026

Copy link
Copy Markdown
Contributor

Task: #1923 C3 \u2014 Agent tools for Notes/Todo split.

Changes

  • New: tinyagentos/tools/todo_tools.py with execute_todo_list_lists, execute_todo_add_item, execute_todo_set_done
  • New: tinyagentos/todo/notify.py \u2014 notification placeholder for when collaboration lands on TodoStore
  • New: tests/todo/test_todo_tools.py \u2014 17 tests covering list/add/set_done with owner-based access control
  • Removed: execute_notes_set_done from notes_tools.py (set_done now lives on TodoStore)
  • Removed: notes_set_done tests from tests/notes/test_notes_tools.py (11 remaining tests pass)
  • Updated: skill_exec.py \u2014 replaced _skill_notes_set_done with _skill_todo_list_lists/_skill_todo_add_item/_skill_todo_set_done
  • Updated: skills.py \u2014 replaced notes_set_done skill seed with 3 todo skills

Tests

  • pytest tests/todo/test_todo_tools.py -v --timeout=120 \u2014 17/17 pass
  • pytest tests/notes/test_notes_tools.py -v --timeout=120 \u2014 11/11 pass
  • pytest tests/todo/test_todo_routes.py -v --timeout=120 \u2014 36/36 pass (no regressions)

Design note

TodoStore uses owner-based access control (no agent membership yet). The owner_user_id arg gates access \u2014 agents must present a matching owner to list/add/set-done. When collaboration lands on TodoStore (C1 follow-up), this will shift to member-based permission checks. The notification path (todo/notify.py) is a no-op placeholder ready for that upgrade.

Summary by CodeRabbit

  • New Features

    • Added built-in todo skills to list todo lists, add items, and set completion status.
    • Todo operations now enforce owner-based authorization with clearer archived/missing resource errors.
    • Added todo notification scaffolding for item updates (best-effort, currently no-op).
  • Changes

    • Removed the prior “notes completion” skill; notes functionality is limited to shared-doc listing and entry creation.
    • Skill discovery now only advertises skills that have active implementations.
  • Documentation

    • Updated agent manuals to reflect the todo list/item API (replacing the old notes completion API).
  • Tests

    • Expanded todo tool test coverage; trimmed notes tool completion coverage.

@hognek
hognek marked this pull request as ready for review July 19, 2026 09:15
@qodo-code-review

Copy link
Copy Markdown

Qodo reviews are paused for this user.

Troubleshooting steps vary by plan Learn more →

On a Teams plan?
Reviews resume once this user has a paid seat and their Git account is linked in Qodo.
Link Git account →

Using GitHub Enterprise Server, GitLab Self-Managed, or Bitbucket Data Center?
These require an Enterprise plan - Contact us
Contact us →

@coderabbitai

coderabbitai Bot commented Jul 19, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@hognek, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 47 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 4dbefaf2-118b-4dc7-bc33-e34ee9dbb3fd

📥 Commits

Reviewing files that changed from the base of the PR and between 3a76215 and 8b82b41.

📒 Files selected for processing (1)
  • tinyagentos/skills.py
📝 Walkthrough

Walkthrough

Todo list and item tools now resolve ownership, validate access and resources, and support listing, adding, and completion updates. These tools are registered as built-in skills and documented. The notes completion handler and its tests are removed, and a GitHub secret mock is made key-aware.

Changes

Todo skill migration

Layer / File(s) Summary
Todo tool behavior and coverage
tinyagentos/tools/todo_tools.py, tinyagentos/todo/notify.py, tests/todo/*
Adds ownership resolution, validation, TodoStore updates, notification handling, and comprehensive todo tool tests.
Todo skill registration
tinyagentos/skills.py, tinyagentos/routes/skill_exec.py
Registers the three todo skills, removes orphaned notes completion rows, and filters discovery to implemented skills.
Notes completion retirement and documentation
tinyagentos/tools/notes_tools.py, tests/notes/test_notes_tools.py, docs/agent-manual/*, docs/taos-agent-manual.md
Removes the notes completion handler and updates manuals for todo-list operations and revised desktop guidance.

GitHub test fixture

Layer / File(s) Summary
Key-aware secret mock
tests/test_routes_github.py
Updates mocked secret lookup to return values based on the requested key.

Estimated code review effort: 3 (Moderate) | ~25 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Agent
  participant SkillExecution
  participant TodoTools
  participant TodoStore
  participant TodoNotifications
  Agent->>SkillExecution: invoke todo skill
  SkillExecution->>TodoTools: delegate operation
  TodoTools->>TodoStore: list, add, or patch todo data
  TodoTools->>TodoNotifications: trigger add-item notifications
  TodoNotifications-->>TodoTools: complete as a no-op
  TodoTools-->>Agent: return structured result or error
Loading

Possibly related PRs

  • jaylfc/taOS#1457: Also changes SKILL_IMPLEMENTATIONS wiring in skill_exec.py.
  • jaylfc/taOS#1460: Also adds tool keys to skill discovery and implementation mappings.
  • jaylfc/taOS#1480: Directly conflicts with this PR over the notes_set_done tool surface.

Suggested reviewers: jaylfc

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 51.22% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly states the main change: adding todo list agent tools and removing notes_set_done.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@gitar-bot

gitar-bot Bot commented Jul 19, 2026

Copy link
Copy Markdown

Gitar is working

Gitar


try:
store = request.app.state.todo_store
lists = await store.list_lists(owner_user_id)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

WARNING: agent_name is never used to authorize the list read — any agent can enumerate another user's todo lists by supplying an arbitrary owner_user_id.

Unlike execute_notes_list_shared_docs (which filters via docs_for_agent(agent_name)), this returns list_lists(owner_user_id) for whatever id the caller passes. There is no check that the calling agent is associated with that owner, so any agent that guesses/learns another user's user_id can read their private lists. This is the same gap flagged across the todo tools (see below). If this is intentional for the "owner-based, no membership yet" phase, please document the trust boundary explicitly and tighten it once C1 collaboration lands.


Reply with @kilocode-bot fix it to have Kilo Code address this issue.

return {"error": "list not found"}
if doc.get("archived_at") is not None:
return {"error": "list is archived"}
if doc.get("owner_user_id") != owner_user_id:

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

WARNING: Access gate is doc.get("owner_user_id") != owner_user_id only — the supplied owner_user_id is trusted verbatim, with no binding to agent_name.

Any agent that knows a victim's user_id can add items to that user's list. There is no membership/permission check analogous to notes_tools (agent_members + permission level). The agent_name parameter is validated as a string but otherwise unused for authorization here. Consider binding the agent to a verified owner/tenant context rather than accepting the owner id from the agent payload.


Reply with @kilocode-bot fix it to have Kilo Code address this issue.

return {"error": "list not found"}
if doc.get("archived_at") is not None:
return {"error": "list is archived"}
if doc.get("owner_user_id") != owner_user_id:

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

WARNING: Same owner-id-only authorization gap as execute_todo_add_item (line 64). The owner_user_id is caller-supplied and never tied to agent_name, so any agent knowing a user id can toggle completion on that user's items.


Reply with @kilocode-bot fix it to have Kilo Code address this issue.

Comment thread tinyagentos/tools/todo_tools.py Outdated
try:
store = request.app.state.todo_store
lists = await store.list_lists(owner_user_id)
return {"lists": lists}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

SUGGESTION: execute_todo_list_lists returns the full list rows, leaking internal fields (owner_user_id, archived_at, created_at) to the agent. The skill schema description advertises only id, title, updated_at. The notes equivalent (notes_list_shared_docs) explicitly strips owner_user_id (see tests/notes/test_notes_tools.py which asserts owner_user_id not in keys). Consider projecting a safe subset here too.

Suggested change
return {"lists": lists}
lists = await store.list_lists(owner_user_id)
return {"lists": [{k: l[k] for k in ("id", "title", "updated_at") if k in l} for l in lists]}

Reply with @kilocode-bot fix it to have Kilo Code address this issue.

@kilo-code-bot

kilo-code-bot Bot commented Jul 19, 2026

Copy link
Copy Markdown

Code Review Summary

Status: No Issues Found | Recommendation: Merge

Files Reviewed (9 files)
  • docs/agent-manual/04-apps.md
  • docs/agent-manual/09-os-control.md
  • docs/taos-agent-manual.md
  • tests/test_routes_github.py
  • tests/todo/test_todo_tools.py
  • tinyagentos/routes/skill_exec.py
  • tinyagentos/skills.py
  • tinyagentos/todo/notify.py
  • tinyagentos/tools/todo_tools.py
Previous Review Summary (commit 93205fe)

Current summary above is authoritative. Previous snapshots are kept for context only.

Previous review (commit 93205fe)

Status: No Issues Found | Recommendation: Merge

Files Reviewed (11 files)
  • docs/agent-manual/04-apps.md
  • docs/agent-manual/09-os-control.md
  • docs/taos-agent-manual.md
  • tests/notes/test_notes_tools.py
  • tests/test_routes_github.py
  • tests/todo/test_todo_tools.py
  • tinyagentos/routes/skill_exec.py
  • tinyagentos/skills.py
  • tinyagentos/todo/notify.py
  • tinyagentos/tools/notes_tools.py
  • tinyagentos/tools/todo_tools.py

Reviewed by step-3.7-flash · Input: 154.2K · Output: 40K · Cached: 2M

@hognek
hognek force-pushed the feat/1923-notes-todo-agent-tools branch from 0c01276 to 535b9f0 Compare July 19, 2026 15:07

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (1)
tests/todo/test_todo_tools.py (1)

42-52: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Add an explicit assertion that internal fields are stripped.

This test verifies the allowlisted list response but never asserts that internal fields (owner_user_id, archived_at, created_at) are absent — the exact contract previously flagged as leaking. The notes-tools equivalent explicitly asserts owner_user_id not in keys; mirroring that here would guard against regression if the allowlist in execute_todo_list_lists is ever loosened.

     assert "lists" in res
     assert any(d["id"] == doc["id"] for d in res["lists"])
     assert len(res["lists"]) == 1
+    for d in res["lists"]:
+        assert "owner_user_id" not in d
+        assert "archived_at" not in d
+        assert "created_at" not in d
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/todo/test_todo_tools.py` around lines 42 - 52, Extend
test_list_returns_owned_lists to explicitly verify that each returned list omits
the internal fields owner_user_id, archived_at, and created_at, while preserving
the existing ownership, inclusion, and count assertions.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@tinyagentos/tools/todo_tools.py`:
- Around line 71-80: In both execute_todo_add_item and execute_todo_set_done,
perform the owner_user_id authorization check immediately after confirming the
list exists, before evaluating archived_at. Return the existing generic
access-denied error for non-owners, while preserving the archived-list response
for authorized owners.
- Around line 17-41: Bind todo-tool authorization to the calling agent rather
than trusting the LLM-supplied owner_user_id. Update execute_todo_list_lists and
the corresponding add-item and mark-done functions to derive or validate
ownership through the authenticated agent identity and reject mismatches before
accessing TodoStore; preserve owner_user_id only as a validated target when it
matches that identity or an established membership relationship.

---

Nitpick comments:
In `@tests/todo/test_todo_tools.py`:
- Around line 42-52: Extend test_list_returns_owned_lists to explicitly verify
that each returned list omits the internal fields owner_user_id, archived_at,
and created_at, while preserving the existing ownership, inclusion, and count
assertions.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: a0bc0ef9-4eca-4e38-b2f7-ba1480e298c5

📥 Commits

Reviewing files that changed from the base of the PR and between 514d947 and 535b9f0.

📒 Files selected for processing (8)
  • tests/notes/test_notes_tools.py
  • tests/test_routes_github.py
  • tests/todo/test_todo_tools.py
  • tinyagentos/routes/skill_exec.py
  • tinyagentos/skills.py
  • tinyagentos/todo/notify.py
  • tinyagentos/tools/notes_tools.py
  • tinyagentos/tools/todo_tools.py
💤 Files with no reviewable changes (2)
  • tinyagentos/tools/notes_tools.py
  • tests/notes/test_notes_tools.py

Comment thread tinyagentos/tools/todo_tools.py Outdated
Comment thread tinyagentos/tools/todo_tools.py
hognek added a commit to hognek/tinyagentos that referenced this pull request Jul 19, 2026
Resolve owner_user_id from the agent registry (get_by_handle) instead of
trusting the caller-supplied value, closing the authorization gap where any
agent knowing a user_id could enumerate, write to, or toggle another user's
todo lists.

- Add _resolve_owner_user_id() helper: looks up agent_name in agent_registry,
  returns the verified user_id when registry is available (production),
  falls back to args-supplied owner_user_id when absent (test compat).
- execute_todo_list_lists: requires agent_name, derives owner from registry.
- execute_todo_add_item: derives owner from registry instead of trusting args.
- execute_todo_set_done: requires agent_name, derives owner from registry.
- New tests: registry enforcement (AsyncMock), unregistered agent rejection,
  fallback without registry. All 21 todo + 11 notes tests pass.

Fixes Kilo WARNINGs on PR jaylfc#2035 (agent auth bypass).
@hognek
hognek force-pushed the feat/1923-notes-todo-agent-tools branch from 43696ce to 4c89156 Compare July 19, 2026 22:14
@jaylfc

jaylfc commented Jul 27, 2026

Copy link
Copy Markdown
Owner

Deep review done against HEAD, not against the bot comments. Worth stating up front: all four kilo warnings were filed on 2026-07-19 against this branch's FIRST commit and were fixed by three later commits on the same branch (adaecd84 binds agent_name via the registry, 4c891566 moves the owner check before the archived check, 20e69f3f/8c680bd9 whitelist the response fields). So the auth findings are stale and there is no security hole at HEAD. Reviewing HEAD does turn up a blocking defect that neither bot found.

BLOCKING: the registry binding that fixed the auth findings makes all three tools dead for ordinary deployed agents.

tools/todo_tools.py:34-36 resolves identity with await agent_registry.get_by_handle(agent_name) and returns {"error": "agent not found in registry"} when there is no row. But config-deployed agents, the ones that actually call /api/skill-exec/{id}/call, are never written to agent_registry. The only writers are the four hardcoded internal driver handles in routes/agent_registry.py:326, external self-join in routes/agent_auth_requests.py:489, and routes/coding_sessions.py:117 where the handle is a session id rather than an agent name. app.state.agent_registry is always set (app.py:1665), so the agent_registry is None fallback at todo_tools.py:29-31 never fires in production; it only fires in the tests.

Run against a real AgentRegistryStore:

deployed agent, no registry row        -> {'error': 'agent not found in registry'}
registered handle=atlas user_id=user-1 -> {'lists': [...]}

So merging removes notes_set_done, which works today via membership-gated shared_docs_store.agent_members, and replaces it with three tools that error for every agent the Agents app deploys. It fails closed, so this is a capability regression rather than a security problem, but the three skills are advertised to the model as working.

Smallest fix: in _resolve_owner_user_id, when get_by_handle misses, fall back to the deployed agent's owner via find_agent(config, agent_name) rather than erroring. Alternative: keep notes_set_done registered and land the todo tools additively, which is what the spec's own risk table says in docs/design/notes-todo-split.md ("old tool stays registered until C4 explicitly removes it"); the C3 bullet at line 331 contradicts it. The real fix is minting registry identities at deploy time, which is slice 8 of #1800 and out of scope here.

Why 17 green tests missed it. No skip guards, all imports resolve, 32 passed when I ran them, so the tests are real. The gap is coverage: 13 of 17 pass agent_registry=None and therefore exercise the args-trusting fallback, which is the path the bots flagged as insecure; the 4 registry tests use a MagicMock whose get_by_handle returns a row by construction. No test instantiates a real AgentRegistryStore, so the handle-not-found case, the only case that occurs in production, is never exercised. The field whitelist at todo_tools.py:62-65 is also untested; tests/notes/test_notes_tools.py:199 has the equivalent assertion worth copying.

Other pre-merge asks:

  • tests/test_routes_github.py:341-360 (commit 3534fb08) re-adds mock_config.github_app_private_key and deletes the two comments recording that the key moved out of config in fix(security): move GitHub App RSA key from plaintext config to SecretsStore #2009. origin/dev has not touched that file since the merge base, so this lands as a straight revert of that hardening. I ran dev's version of the file against this branch's code: 19 passed, so the edit was unnecessary. Please drop that file from the PR.
  • docs/taos-agent-manual.md:188 and docs/agent-manual/09-os-control.md:44 still document notes_set_done. After merge that skill has no entry in SKILL_IMPLEMENTATIONS, so the endpoint returns 501 while the manual advertises it, and the three new tools are documented nowhere. doc-gate does not catch this. Update both in the same batch.
  • Consider dropping owner_user_id from the three input_schema blocks in skills.py. It is marked required but is overridden by the registry, so the model is asked for a value it cannot know and that has no effect.
  • tinyagentos/todo/notify.py is a 32-line no-op with four unused parameters. Defensible as a marked seam, but flagging it against the nothing-speculative rule.

Checks that came back clean: the branch is 62 commits behind dev but dev's only change to todo_store.py is reorder_items, which this PR does not call, and skill_exec.py/skills.py have zero dev-side drift; I simulated the merge onto current dev and ran the affected suites, 140 passed. CI is genuinely green with real durations rather than the fork action_required trap. notes_set_done has no remaining callers outside the files this PR touches. House style matches routes/secrets.py:57-64 and notes_tools.py closely.

hognek added a commit to hognek/tinyagentos that referenced this pull request Jul 27, 2026
When agent_registry.get_by_handle misses (deployed agents are never in
the registry), fall back to find_agent(config, agent_name) and use
request.state.user_id (set by local-token auth for the primary user).

Also: revert github_app_private_key mock regression (tests/test_routes_github.py),
drop owner_user_id from todo input_schemas (skills.py), replace notes_set_done
with todo tools in docs, flag notify.py no-op, add internal-field strip assertions
and deployed-agent fallback tests.

jaylfc review fixes for jaylfc#2035.
@hognek

hognek commented Jul 27, 2026

Copy link
Copy Markdown
Contributor Author

All five points addressed in 93205fe:

  1. BLOCKING fix: _resolve_owner_user_id now falls back to find_agent(config, agent_name) when get_by_handle misses, using request.state.user_id (local-token auth → primary user) as the owner for deployed agents. Registry binding still takes priority for registered agents.

  2. github_app_private_key mock: Reverted to dev version — mock_config.github_app_private_key removed, comments restored referencing fix(security): move GitHub App RSA key from plaintext config to SecretsStore #2009.

  3. Docs: notes_set_done replaced with todo_list_lists / todo_add_item / todo_set_done in both docs/taos-agent-manual.md and docs/agent-manual/09-os-control.md.

  4. owner_user_id in input_schemas: Dropped from all three todo skill tool_schema.input_schema blocks in skills.pyrequired arrays shrunk accordingly.

  5. notify.py no-op: Flagged with explicit NOTE comment stating it is a deliberate placeholder seam.

Tests: 34/34 pass (todo_tools + notes_tools), 19/19 pass (routes_github). New tests: deployed-agent fallback (agent in config → uses state.user_id), deployed agent without user_id → error, agent in neither registry nor config → error. Added internal-field strip assertions on list response.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (4)
tinyagentos/routes/skill_exec.py (1)

431-436: 🩺 Stability & Availability | 🔵 Trivial | ⚡ Quick win

Avoid blanket exception handling in the skill wrappers.

The Todo implementations already convert expected failures into {"error": ...} results. These additional except Exception blocks can swallow unexpected import or programming errors and prevent execute_skill from applying its centralized failure handling. Remove the wrapper-level catches or restrict them to documented exceptions while re-raising unexpected failures.

Also applies to: 441-446, 451-456

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tinyagentos/routes/skill_exec.py` around lines 431 - 436, Remove the broad
except Exception wrappers around the Todo, and the corresponding skill wrapper
calls at the referenced locations, so unexpected import or programming errors
propagate to execute_skill’s centralized failure handling. Preserve the direct
await-and-return behavior and retain only explicitly documented exception
handling if required by the underlying implementations.

Source: Linters/SAST tools

tests/todo/test_todo_tools.py (2)

56-60: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Drop the review-tool reference from the assertion comment.

The assertions are self-explanatory; referencing a bot nitpick/issue number ages poorly in the test suite.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/todo/test_todo_tools.py` around lines 56 - 60, Remove the “CodeRabbit
nitpick, `#2035`” reference from the comment above the assertions in the
res["lists"] loop, leaving a concise comment or no comment while preserving all
assertions unchanged.

361-394: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Deployed-agent fallback is only covered for todo_list_lists.

execute_todo_add_item / execute_todo_set_done route through the same resolver but have no config-fallback test, so a regression in their ownership path (e.g. resolver call moved after the store read) would go unnoticed. Consider parametrizing the fallback tests across all three tools.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/todo/test_todo_tools.py` around lines 361 - 394, Extend the
deployed-agent fallback coverage from execute_todo_list_lists to
execute_todo_add_item and execute_todo_set_done, preferably by parametrizing the
existing fallback tests across all three tool functions. Verify each tool uses
request.state.user_id when registry lookup fails but the agent is present in
config, and add corresponding no-user_id rejection coverage if the shared
behavior requires it.
tinyagentos/tools/todo_tools.py (1)

83-84: 🔒 Security & Privacy | 🔵 Trivial | ⚡ Quick win

Blind except Exception returns raw str(exc) to the agent.

Flagged by Ruff (BLE001). Beyond the lint, propagating internal exception text (DB paths, driver messages) into the tool response is unnecessary detail for the model. Prefer logging the exception and returning a generic message.

♻️ Proposed pattern (apply to all three handlers)
-    except Exception as exc:
-        return {"error": str(exc)}
+    except Exception:  # noqa: BLE001
+        logger.exception("todo_list_lists failed")
+        return {"error": "todo_list_lists failed"}

Also applies to: 139-140, 191-192

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tinyagentos/tools/todo_tools.py` around lines 83 - 84, Update all three tool
handlers’ broad exception handlers to log the caught exception with the module’s
existing logger, then return a generic user-facing error message instead of raw
str(exc). Address the handlers at the cited locations consistently and preserve
their existing response structure.

Source: Linters/SAST tools

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@tinyagentos/tools/todo_tools.py`:
- Around line 70-71: Update the None-handling error responses in the
deployed-agent paths of _resolve_owner_user_id callers to distinguish an unset
request.state.user_id from an agent missing in the registry. Use a message that
accurately describes the missing owner/user identity, and apply the same
correction to the corresponding responses at the other referenced locations.

---

Nitpick comments:
In `@tests/todo/test_todo_tools.py`:
- Around line 56-60: Remove the “CodeRabbit nitpick, `#2035`” reference from the
comment above the assertions in the res["lists"] loop, leaving a concise comment
or no comment while preserving all assertions unchanged.
- Around line 361-394: Extend the deployed-agent fallback coverage from
execute_todo_list_lists to execute_todo_add_item and execute_todo_set_done,
preferably by parametrizing the existing fallback tests across all three tool
functions. Verify each tool uses request.state.user_id when registry lookup
fails but the agent is present in config, and add corresponding no-user_id
rejection coverage if the shared behavior requires it.

In `@tinyagentos/routes/skill_exec.py`:
- Around line 431-436: Remove the broad except Exception wrappers around the
Todo, and the corresponding skill wrapper calls at the referenced locations, so
unexpected import or programming errors propagate to execute_skill’s centralized
failure handling. Preserve the direct await-and-return behavior and retain only
explicitly documented exception handling if required by the underlying
implementations.

In `@tinyagentos/tools/todo_tools.py`:
- Around line 83-84: Update all three tool handlers’ broad exception handlers to
log the caught exception with the module’s existing logger, then return a
generic user-facing error message instead of raw str(exc). Address the handlers
at the cited locations consistently and preserve their existing response
structure.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: f297ae7a-8cce-4dfe-b5c8-12f6bd3ca511

📥 Commits

Reviewing files that changed from the base of the PR and between 535b9f0 and 93205fe.

📒 Files selected for processing (10)
  • docs/agent-manual/09-os-control.md
  • docs/taos-agent-manual.md
  • tests/notes/test_notes_tools.py
  • tests/test_routes_github.py
  • tests/todo/test_todo_tools.py
  • tinyagentos/routes/skill_exec.py
  • tinyagentos/skills.py
  • tinyagentos/todo/notify.py
  • tinyagentos/tools/notes_tools.py
  • tinyagentos/tools/todo_tools.py
💤 Files with no reviewable changes (2)
  • tests/notes/test_notes_tools.py
  • tinyagentos/tools/notes_tools.py
🚧 Files skipped from review as they are similar to previous changes (3)
  • tinyagentos/todo/notify.py
  • tinyagentos/skills.py
  • tests/test_routes_github.py

Comment thread tinyagentos/tools/todo_tools.py Outdated
@jaylfc

jaylfc commented Jul 27, 2026

Copy link
Copy Markdown
Owner

Fast turnaround, thank you, and your resolve owner for deployed agents via config fallback commit is exactly the right fix for F1.

The red is NOT your logic, and it is partly my fault for not flagging the constraint when I asked for the doc update.

FAILED tests/test_agent_manual_compiled.py::test_compiled_size_under_limit
AssertionError: Compiled manual is 16175 chars, exceeds 16000 limit.
1 failed, 2571 passed

The agent manual has a hard SIZE BUDGET of 16000 chars because the compiled output is injected into small context windows. I asked you to document the three new todo tools and drop the stale notes_set_done entry, and the net addition pushed it 175 chars over. Everything else on the branch passes.

Three ways out, in the order I would try them:

  1. Trim while you are in there. You are already deleting the notes_set_done entry from docs/taos-agent-manual.md:188 and docs/agent-manual/09-os-control.md:44; make sure BOTH deletions actually landed, since removing one and adding three would explain the overshoot neatly. 175 chars is roughly two sentences.
  2. Write the three new tools more tersely. The manual is a prompt, not reference docs: one line per tool with args is enough, and the input_schema in skills.py is the real contract.
  3. Only if 1 and 2 fail: raise the cap in tests/test_agent_manual_compiled.py, but justify it in the PR. The number exists to keep the manual injectable on a small model, so raising it silently defeats the check rather than satisfying it.

Please do not resolve it by dropping the doc update. Shipping three skills the manual does not describe, while it still advertises one that returns 501, is the state I asked you to fix.

Everything else from my earlier review still stands: the registry-miss test with a real AgentRegistryStore (F2), reverting tests/test_routes_github.py out of the PR (F7), and considering dropping the now-ignored owner_user_id from the three input_schema blocks.

hognek added 8 commits July 28, 2026 00:11
Create todo_tools.py with execute_todo_list_lists, execute_todo_add_item,
and execute_todo_set_done. Register in skill_exec.py SKILL_IMPLEMENTATIONS
and skills.py seed data. Remove deprecated execute_notes_set_done from
notes_tools.py (set_done now lives on TodoStore).

Add tests/todo/test_todo_tools.py (17 tests) covering list/add/set_done
with owner-based access control. Remove notes_set_done tests from
tests/notes/test_notes_tools.py (11 remaining tests pass).

Task: 1923 C3 — Notes/Todo split agent tool surface.
… model

Address Kilo bot findings:
- Filter owner_user_id/archived_at/created_at from list_lists response
- Add docstring notes explaining owner-based authorization model and the
  planned agent_name-to-owner binding for when TodoStore gains membership

No CRITICAL findings. 17/17 todo tools, 11/11 notes tools, 18/18 todo routes pass.
Match the skill schema description which advertises only id, title, updated_at.
Using a whitelist (not blacklist) is the safer pattern — new fields added to
the store row won't leak through by default.
…ument auth boundary

Remove agent_name validation from execute_todo_list_lists and
execute_todo_set_done — the parameter was accepted but never used.
It was injected by skill_exec.py but served no purpose, creating a
false expectation that agent_name participates in authorization.

For execute_todo_add_item, agent_name is still required (used for
attribution and notification skip-guard). Add explicit SECURITY
comments at each owner_user_id check documenting that agent-to-owner
binding awaits agent membership on TodoStore (jaylfc#1923 follow-up).

The internal field leak in list_lists was already fixed (allowlist
projection at line 39).
…eturn private key for github-app-private-key lookups

The test helper _build_app_with_app_config(token=None) set mock_secrets.get
to return None for ALL keys, causing _get_app_installation_token to fail
when looking up the GitHub App private key. Now it returns the key for
github-app-private-key lookups while keeping PAT behavior unchanged.

Fixes CI failure: test_repo_endpoint_still_uses_app_token (401 vs 200).
All 4 tests using _build_app_with_app_config now pass.
Resolve owner_user_id from the agent registry (get_by_handle) instead of
trusting the caller-supplied value, closing the authorization gap where any
agent knowing a user_id could enumerate, write to, or toggle another user's
todo lists.

- Add _resolve_owner_user_id() helper: looks up agent_name in agent_registry,
  returns the verified user_id when registry is available (production),
  falls back to args-supplied owner_user_id when absent (test compat).
- execute_todo_list_lists: requires agent_name, derives owner from registry.
- execute_todo_add_item: derives owner from registry instead of trusting args.
- execute_todo_set_done: requires agent_name, derives owner from registry.
- New tests: registry enforcement (AsyncMock), unregistered agent rejection,
  fallback without registry. All 21 todo + 11 notes tests pass.

Fixes Kilo WARNINGs on PR jaylfc#2035 (agent auth bypass).
… leak

Move the owner_user_id gate before the archived_at gate in both
execute_todo_add_item and execute_todo_set_done. Previously a non-owner
caller who guessed a valid list_id could learn whether the list was
archived. Now the owner check runs first, returning a uniform 'access
denied' error for non-owners regardless of archived state.
When agent_registry.get_by_handle misses (deployed agents are never in
the registry), fall back to find_agent(config, agent_name) and use
request.state.user_id (set by local-token auth for the primary user).

Also: revert github_app_private_key mock regression (tests/test_routes_github.py),
drop owner_user_id from todo input_schemas (skills.py), replace notes_set_done
with todo tools in docs, flag notify.py no-op, add internal-field strip assertions
and deployed-agent fallback tests.

jaylfc review fixes for jaylfc#2035.
@hognek
hognek force-pushed the feat/1923-notes-todo-agent-tools branch from 93205fe to 471c98b Compare July 27, 2026 22:25
… blanket excepts

- todo_tools.py: Change 'agent not found in registry' to precise message
  covering both missing-agent and missing-user_id cases (CR inline jaylfc#2035).
- todo_tools.py: Replace raw str(exc) blanket excepts with logged generic
  messages (CR nitpick, BLE001).
- skill_exec.py: Remove try/except wrappers on 3 _skill_todo_* functions
  so unexpected errors propagate to centralized handler (CR nitpick).
- test_todo_tools.py: Remove CodeRabbit nitpick reference from comment.
- test_todo_tools.py: Extend deployed-agent fallback coverage to
  execute_todo_add_item and execute_todo_set_done (4 new tests).

Tests: 27/27 todo tools pass (includes 4 new), 11/11 notes tools pass.
@hognek
hognek force-pushed the feat/1923-notes-todo-agent-tools branch from 471c98b to 1dc3b7f Compare July 27, 2026 22:35
@jaylfc

jaylfc commented Jul 27, 2026

Copy link
Copy Markdown
Owner

Re-reviewed at head 1dc3b7fe. The blocking finding is genuinely closed, and I traced the whole production path rather than taking the commit message's word for it. Merged onto current origin/dev it is a clean merge and 157 tests pass.

# Finding Status
F1 BLOCKING: registry binding kills all three tools for deployed agents FIXED (todo_tools.py:44-53)
F2 Registry-miss never exercised with a real store; field whitelist untested PARTIAL
F3 test_routes_github.py reverts #2009 hardening FIXED
F4 Docs still advertise notes_set_done FIXED
F5 Drop owner_user_id from the three input_schema blocks FIXED
F6 notify.py speculative no-op Annotated, acceptable
F7 Compiled manual over the 16000-char budget FIXED

On F1, the chain I verified: /api/skill-exec/* is not exempt (auth_middleware.py:12,170,275), deployed agents present TAOS_LOCAL_TOKEN (routes/skill_exec.py:29-49), the local-token branch sets request.state.user_id = primary["id"] (auth_middleware.py:368-372), app.state.config is set (app.py:1544), and UI-created lists are owned by that same id (routes/todo.py:104). The fallback resolves. Good fix.

Before merge I want three things, none large:

1. The head commit has had zero automated review. Kilo Code Review is red, and it is not a code finding: the check output is Review failed: Assistant request was rate limited. CodeRabbit reports pass on the same head with "Review rate limited", which is the fake-green I have flagged before. Eight shards, lint, doc-gate, spa-build and cla are genuinely green, so this is safe to re-run rather than waive. Please push or re-trigger so Kilo actually reads 1dc3b7fe.

2. F2 is still not what I asked for, and it is cheap. The registry-miss path now has six tests (tests/todo/test_todo_tools.py:346-473) but every one uses MagicMock() with AsyncMock(return_value=None). Nothing in tests/todo/ instantiates a real AgentRegistryStore, and nothing exercises execute_skill through AuthMiddleware. The fixture pattern already exists at tests/test_registry_governance_lifecycle.py:35. Credit where due: a straight revert of the F1 fix would now go red, which is the property that matters most, so this is a strengthening request rather than a blocker on its own.

3. The existing-install orphan, which is the real remaining defect and nobody has caught it. Nothing removes the seeded notes_set_done row. Seeding is INSERT OR IGNORE on every startup (skills.py:37-42), so the row survives upgrade. list_tools (routes/skill_exec.py:489-497) builds the agent's tool list straight from get_agent_skills with no cross-check against SKILL_IMPLEMENTATIONS. So any agent that already had notes_set_done assigned keeps being advertised a tool that now 501s on call. Assignment is manual so the blast radius is small, but this is exactly the existing-DB upgrade path we keep getting caught by, and there is no test over it. Either add a removal migration or filter list_tools by SKILL_IMPLEMENTATIONS. Please test it against a DB seeded BEFORE this change, not a fresh one, or the test cannot fail.

Three smaller things, not blockers, worth a look:

  • author=agent_name in todo_tools.py:118 versus author=user.user_id in routes/todo.py:195. Same column, two id spaces, so the Todo UI may render an agent name where it expects a user id.
  • get_by_handle defaults to status="active" (agent_registry_store.py:542), so a REVOKED registry identity that is also a config agent misses the registry lookup and then silently succeeds via the config fallback. Low severity behind the local-token gate, but the ordering deserves a comment so nobody widens that gate later without noticing.
  • The three _skill_todo_* wrappers lost their try/except (skill_exec.py:429-450) while the notes wrappers kept theirs, so a todo-tool import error now surfaces as a 500 rather than a 200 with an error body. Arguably more correct, just asymmetric.

One note on how F7 was fixed: the manual is now 15965 chars against the 16000 budget, so 35 chars of headroom, and some of that was bought by trimming unrelated prose (docs/agent-manual/04-apps.md:20, 09-os-control.md:3-4,36). That works, but the next person to add a tool line hits the wall immediately. Worth raising the budget deliberately in a separate PR rather than trimming prose again under pressure.

- author=agent_name -> owner_user_id in todo_tools.py:138 (id space mismatch)
- real AgentRegistryStore tests (not MagicMock) for registry-miss path
- notes_set_done orphan cleanup in SkillStore._post_init
- list_tools filters against SKILL_IMPLEMENTATIONS
@hognek

hognek commented Jul 28, 2026

Copy link
Copy Markdown
Contributor Author

F2 fix (3a76215): Added field-whitelist assertions to test_registry_hit_uses_store_user_id — the real-store registry-hit path now verifies that owner_user_id, archived_at, and created_at are stripped from the response.

The real AgentRegistryStore tests were already added in the prior commit (890511e), covering:

  • Registry hit → uses registry user_id (real store, 3a76215 now adds whitelist assertions)
  • Registry miss → config fallback (real store, empty DB)
  • Registry miss → no config → error (real store, empty DB)

Together with the existing agent_registry=None whitelist test (line 56-60), the whitelist behavior is now verified in both the null-registry and real-store paths.

30/30 tests pass: pytest tests/todo/test_todo_tools.py -v --timeout=120

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@tinyagentos/skills.py`:
- Around line 42-44: Update _remove_orphan_skills to migrate each existing
notes_set_done assignment to todo_set_done before deleting the legacy
assignment. Preserve the assigned agents’ completion access, and reset or clear
any legacy configuration that is specific to Notes before removing the old rows.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 33a81320-c280-4f93-8646-07e2b78ad798

📥 Commits

Reviewing files that changed from the base of the PR and between 93205fe and 3a76215.

📒 Files selected for processing (11)
  • docs/agent-manual/04-apps.md
  • docs/agent-manual/09-os-control.md
  • docs/taos-agent-manual.md
  • tests/notes/test_notes_tools.py
  • tests/test_routes_github.py
  • tests/todo/test_todo_tools.py
  • tinyagentos/routes/skill_exec.py
  • tinyagentos/skills.py
  • tinyagentos/todo/notify.py
  • tinyagentos/tools/notes_tools.py
  • tinyagentos/tools/todo_tools.py
💤 Files with no reviewable changes (2)
  • tests/notes/test_notes_tools.py
  • tinyagentos/tools/notes_tools.py
🚧 Files skipped from review as they are similar to previous changes (6)
  • docs/agent-manual/09-os-control.md
  • tinyagentos/todo/notify.py
  • tests/todo/test_todo_tools.py
  • docs/taos-agent-manual.md
  • tests/test_routes_github.py
  • tinyagentos/tools/todo_tools.py

Comment thread tinyagentos/skills.py
_remove_orphan_skills previously deleted agent_skills rows for
notes_set_done without migrating them to todo_set_done. Agents that
had completion access via notes_set_done silently lost it after
startup.

Now the method uses an _ORPHAN_REPLACEMENTS dict that maps each
orphaned skill id to its replacement. Before deleting, it copies
agent assignments to the replacement via INSERT OR IGNORE — if the
agent already has the replacement, the existing newer assignment is
preserved; otherwise the legacy assignment is migrated so access is
not lost.
@hognek

hognek commented Jul 28, 2026

Copy link
Copy Markdown
Contributor Author

Fix pushed for the CodeRabbit finding re: _remove_orphan_skills.

What changed: The method now maintains an _ORPHAN_REPLACEMENTS dict (old → new skill id) instead of a plain list. Before deleting the orphan skill and its agent assignments, it migrates agents to the replacement via INSERT OR IGNORE:

INSERT OR IGNORE INTO agent_skills (agent_id, skill_id, enabled, config)
SELECT agent_id, ?, enabled, config FROM agent_skills WHERE skill_id = ?

If the agent already has todo_set_done assigned, the existing (newer) assignment is preserved. Otherwise the legacy notes_set_done assignment is migrated so agents do not silently lose completion access after startup.

Tests: pytest tests/test_skills.py -v — 6/6 pass. Canonical gate still running (~10K items, ~3% at time of push).

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.

2 participants