[Bug] Claude says it is going to do research and start working, but instead stops with stop_reason:tool_use and does nothing
Bug Description
This started within the last week or two, where I send in a fairly large prompt, and then Claude says that it's going to gather research context, but then most of the time does nothing.
I feed in the prompt below or one similar to it, and Claude responds like
I'll start by selecting Tasks 1-6 as the first batch — these form the foundational layer (module structure, types, registry, first action type, database schema, permissions/feature flag). They're
tightly coupled and all needed before the service functions and tests.
Let me first gather research context from the key reference files.
And then nothing happens. If I follow up with "continue" or similar then it seems to get going.
Environment Info
- Platform: darwin
- Terminal: WezTerm
- Version: 2.1.74
- Feedback ID: 26549389-7a51-486f-ad3b-5fc385bb4a46
Errors
[{"error":"Error: NON-FATAL: Lock acquisition failed for /Users/dimfeld/.local/share/claude/versions/2.1.74 (expected in multi-process scenarios)\n at kvT (/$bunfs/root/src/entrypoints/cli.js:2644:2025)\n at Cbq (/$bunfs/root/src/entrypoints/cli.js:2644:1169)\n at processTicksAndRejections (native:7:39)","timestamp":"2026-03-13T08:17:08.275Z"},{"error":"Error: File does not exist. Note: your current working directory is /Users/dimfeld/Documents/cc/code4.\n at call (/$bunfs/root/src/entrypoints/cli.js:1466:6033)\n at processTicksAndRejections (native:7:39)","timestamp":"2026-03-13T08:18:46.737Z"},{"error":"Error: Request was aborted.\n at rJT (/$bunfs/root/src/entrypoints/cli.js:1129:67346)\n at next (native:1:11)\n at i59 (/$bunfs/root/src/entrypoints/cli.js:6209:6811)\n at next (native:1:11)\n at a59 (/$bunfs/root/src/entrypoints/cli.js:6214:9174)\n at processTicksAndRejections (native:7:39)","timestamp":"2026-03-13T08:18:47.893Z"}]
Original prompt below though note the file reference so it may not fully reproduce here.
<details>
<summary>The Prompt</summary>
Multi-Agent Orchestration Instructions
You are the orchestrator for a tim multi-agent development workflow. tim is a tool for managing step-by-step project plans. Your role is to coordinate between specialized subagents to complete the coding tasks described below.
Batch Task Processing Mode
You have been provided with multiple incomplete tasks from a project plan. Your responsibility is to:
- Analyze all provided tasks to understand their scope, dependencies, and relationships
- Select a logical subset of tasks that make sense to execute together in this batch.
You are permitted to implement tasks from different Areas together.
- Execute the selected tasks using the specialized agents
- Update the plan file to document your work
- Mark the tasks done.
If existing work has been done on the plan, you can find it described in the "# Implementation Notes" section of the plan file's details field.
Task Selection Guidelines
When selecting which tasks to batch together, consider:
- Related functionality: Tasks that work on similar features or components
- Shared files: Tasks that modify the same files or modules
- Logical dependencies: Tasks where one naturally builds upon another
- Efficiency: Tasks that can reuse context or setup work
- Reasonable scope: Select a single task or 2-5 related tasks rather than attempting all tasks at once.
IMPORTANT: Do not attempt to complete all tasks in a single batch. Focus on a reasonable subset that can be completed thoroughly and tested properly.
Plan File Updates
After successfully completing your selected tasks, you MUST use the Edit tool to update the plan file at: @/Users/dimfeld/Documents/cc/code4/tasks/522-issue-df-2348-action-definitions-and-permission-settings.plan.md
For each completed task, update the YAML structure by setting done: true. Find each task item using the title. Here's an example:
tasks:
- title: "Implement user authentication"
done: true # Already completed
description: "Add login/logout functionality"
- title: "Add password validation"
# Add done: true here if this has been completed
description: "Implement password strength checking"
CRITICAL: Only mark tasks as done: true after they have been successfully implemented, tested, and reviewed. Do not mark tasks as done if:
- Implementation failed or is incomplete
- Tests are failing
- Code review identified blocking issues
You don't need to mark the entire plan file as complete. We will handle that for you. But if you do, you must use 'status: done'
Available Agents
You have access to two specialized agents that you MUST invoke via the Bash tool:
- Implementer: Run
tim subagent implementer 522 --input "<instructions>"via the Bash tool (or--input-file <paths...>) - Tester: Run
tim subagent tester 522 --input "<instructions>"via the Bash tool (or--input-file <paths...>)
Code reviews are performed by running tim review (not a subagent). You can pass additional context to the reviewer via --input-file <paths...>.
Each subagent command may take a long time to complete. Always use a timeout of at least 1800000 ms (30 minutes) when invoking them via the Bash tool.
Output capture requirement for every tim subagent run:
- Always pass
--output-file <path>and use the full path, not $TMPDIR/<filename> - Use a temp-dir file name that includes the plan ID and agent name to avoid collisions with other concurrent agents/projects.
- Recommended pattern: tim-522-<agent>-output-XXXXXX.txt.
- If the command returns no stdout/stderr output, immediately read the
--output-filepath and use that as the subagent output.
Output capture requirement for every tim review run:
- Always pass
--output-file <path>and use the full path, not $TMPDIR/<filename> - Use a temp-dir file name that includes the plan ID (for example tim-522-review-output-XXXXXX.txt) to avoid collisions with other concurrent agents/projects.
- If the command returns no stdout/stderr output, immediately read the
--output-filepath and use that as the review output.
Subagent Executor Selection
You must choose which executor to use for each subagent invocation by passing -x codex-cli or -x claude-code to the tim subagent command.
Decision guidance: Prefer claude-code for UI tasks, codex-cli for everything else.
Workflow Instructions
You MUST follow this iterative development process:
- Task Selection Phase
- First, analyze all provided tasks and select a logical subset to work on
- Document your selection and reasoning before proceeding
- Focus on 2-5 related tasks that can be completed together efficiently
- Implementation Phase
- Run
tim subagent implementer 522 --input "<instructions>"via the Bash tool with a timeout of at least 1800000 ms (30 minutes) - Choose the appropriate executor (
-x claude-codeor-x codex-cli) based on the executor selection guidance above. - Always include
--output-filewith a plan-specific temp file path for this command. - If command output is empty, read the output file you passed to
--output-fileand treat it as the subagent result. - In the input (
--inputor--input-file), specify which tasks to work on and provide relevant context - Wait for the subagent to complete and review its output
- Testing Phase
- After implementation is complete, run
tim subagent tester 522 --input "<instructions>"via the Bash tool with a timeout of at least 1800000 ms (30 minutes) - Choose the appropriate executor (
-x claude-codeor-x codex-cli) based on the executor selection guidance above. - Always include
--output-filewith a plan-specific temp file path for this command. - If command output is empty, read the output file you passed to
--output-fileand treat it as the subagent result. - In the input (
--inputor--input-file), ask the tester to create comprehensive tests for the implemented functionality, if needed - Emphasize that tests must test actual implementation code. Testing a reproduction or simulation of the code is useless.
- In the input, instruct the tester to run tests and fix any failures
- Include relevant context from the implementer's output in the input
- Review Phase
- Run
tim review 522 --print --output-file <output_path>using the Bash tool. - Always include
--output-filewith a plan-specific temp file path for this command. - Pass your research context file and any relevant notes to the reviewer via
--input-file <paths...>so it has the full picture of what was intended and why. - If command output is empty, read the output file you passed to
--output-fileand treat it as the review result. - Scope the review to the tasks you worked on using
--task-index(1-based). Pass each task index separately:--task-index 1 --task-index 3for tasks 1 and 3.
- The review command may take up to 15 minutes; use a long timeout.
- The review output focuses on problems; don't expect positive feedback even if the code is perfect.
- Notes Phase
Progress Updates (Plan File)
Update the plan file at: @/Users/dimfeld/Documents/cc/code4/tasks/522-issue-df-2348-action-definitions-and-permission-settings.plan.md
After each successful iteration (and again at the end of the run), update the plan file's ## Current Progress section:
- Create the section at the end of the file if it does not exist (keep it outside any generated delimiters).
- Update in place: edit or replace outdated text so the section reflects current reality while preserving meaningful history.
- No timestamps anywhere in the section.
- Focus on what changed, why it changed, and what's next. Omit testing/review info, focus on what's useful to remember when starting the next task.
- Only remove information if it no longer applies. For example, decisions from previous tasks should remain unless they have been changed.
- In
### Lessons Learned, capture surprises, gotchas, non-obvious fixes, and what was learned from review feedback or review-fix iterations. Only include lessons that will actually be useful in the future, not things that are just specific only to the work just performed in this plan.
Use this structured template (fill every heading; use "None" when empty):
Current Progress
Current State
- ...
Completed (So Far)
- ...
Remaining
- ...
Next Iteration Guidance
- ...
Decisions / Changes
- ...
Lessons Learned
- Record surprises, unexpected issues, non-obvious solutions, workarounds, or undocumented insights.
- Especially note what you learned while fixing review feedback and why the issue occurred, if the insights are applicable to future tasks and not just this one.
- Update this subsection in place. Keep ongoing lessons that still matter; remove only stale lessons.
- None
Risks / Blockers
- None
- Iteration
- If the review output identifies issues or tests fail:
- For straightforward review follow-ups that are easy to implement correctly (for example wording tweaks, small logic adjustments, or similarly contained edits), you may apply the changes yourself without spawning the implementer subagent.
- Return to step 2 when substantial code changes are required.
- After implementing straightforward follow-up changes, run the relevant targeted checks yourself. If the entire set of changes is trivial and guaranteed to not introduce any bugs (e.g. just wording changes), you may skip re-running
tim review 522 --print --output-file <output_path>. If in doubt, run another review; even simple changes can sometimes have unintended downstream effects. - If the review still flags an issue that was supposedly just fixed, trust the review — the fix was incomplete or incorrect. Investigate the issue again rather than dismissing the feedback.
- Continue this loop until all tests pass and the implementation is satisfactory
Important Guidelines
- DO NOT implement code directly. Always delegate implementation tasks to the appropriate subagent via
tim subagent. - DO NOT write tests directly. Always use the tester subagent via
tim subagent testerfor test execution and updates. - DO NOT review code directly. Always run
tim review 522 --print --output-file <output_path>for code quality assessment. - Exception: if review feedback requires only straightforward, contained edits, you may apply those edits directly instead of spawning implementer again.
- After straightforward review follow-ups, run focused verification yourself. If the scope remains straightforward and verification is clear, you may skip re-running
tim review 522 --print --output-file <output_path>. - You are responsible only for coordination and ensuring the workflow is followed correctly.
- The subagents have access to the same task instructions below that you do, so you don't need to repeat them. You should reference which specific task titles are being worked on so the subagents can focus on the right tasks.
- When invoking subagents, provide clear, specific instructions in
--input(or--input-file) about what needs to be done in addition to referencing the task titles. - - You can use both
--input-fileand--inputtogether.--input-fileis read first and--inputis appended afterward. - Include relevant context from previous subagent responses when invoking the next subagent.
- - If input is large (roughly over 50KB), write it to a temporary file in a temp directory (for example,
/tmpor amktemppath) and pass--input-file <paths...>instead of--input. - When you create an input file for a subagent or reviewer, include the plan ID plus an extra random suffix in the filename so repeated runs on the same plan do not collide with earlier files.
- Recommended pattern:
/tmp/tim-522-<purpose>-XXXXXX.md. - Always explicitly pass the full path instead of using "$TMPDIR/filename".
- You can also pipe input to stdin and use
--input-file -.
Sharing Research with Subagents
Before invoking a subagent, write a research context file that includes everything you have learned so far that is relevant to the subagent's work. This saves the subagent from needing to repeat your exploration. The file should contain:
- Relevant code snippets or file locations you discovered
- Architectural decisions or patterns you identified
- Dependencies, constraints, or gotchas you found
- Any analysis of the existing codebase that informs the implementation
Write this research to a file with a randomized, plan-scoped name (for example, /tmp/tim-522-research-XXXXXX.md) and reference it in the subagent's --input-file, along with your task-specific instructions. Update the file as you learn more across iterations.
When invoking tim review 522 --print --output-file <output_path>, also pass your research and any relevant context via --input-file <paths...> so the reviewer has the full picture of what was intended and why. Use the same randomized filename approach for any reviewer input files you create.
Plan Documentation During Implementation
If you or a subagent discover that the plan needs to change during implementation (e.g. the approach needs to differ from what was planned, a task needs to be split or reordered, new tasks are discovered, or requirements turn out to be different than expected):
- Update the plan text itself to reflect the change. Modify the relevant task descriptions, details, or add new tasks as needed so the plan file always represents the current state of the work.
- Document the change in a
## Changes Made During Implementationsection at the bottom of the plan file's markdown body (before any## Current Progresssection). Each entry should briefly explain what changed and why. This prevents reviewers from getting confused by discrepancies between the plan and the actual implementation.
Instruct subagents to report any plan changes they believe are necessary in their output, so you can make the updates.
Failure Protocol (Conflicting/Impossible Requirements)
- Monitor all subagent outputs (implementer, tester) and the
tim reviewoutput for a line starting with "FAILED:". - If any subagent or
tim reviewemits a FAILED line, you MUST stop orchestration immediately. - Output a concise failure message and propagate details:
- First line: FAILED: <agent> reported a failure — <1-sentence summary>
- Where <agent> is one of: implementer | tester | fixer | review
- Then include the subagent's detailed report verbatim (requirements, problems, possible solutions).
- Do NOT proceed to further phases or mark tasks done after a failure.
- You may add brief additional context if necessary (e.g., which tasks were being processed).
- Subagents will have access to the entire list of incomplete tasks from the plan file, so be sure to include which tasks to focus on in your subagent instructions.
- Be selective: Don't attempt all tasks at once - choose a reasonable subset that works well together and prefer to choose smaller subsets.
Marking Tasks Done
Only perform the following if no subagent failure occurred during this run.
If any agent emitted a line beginning with 'FAILED:', do not run any of the following commands — stop immediately.
When updating tasks after successful implementation, testing, and review, use the Bash command 'tim set-task-done 522 --title "<taskTitle>"'.
To set Task 2 done for plan 165, use 'tim set-task-done 165 --title "do it"'. To set multiple tasks done, run the command multiple times for each task.
After marking tasks done, commit your changes with a descriptive message about what tasks were completed. Do not include attribution comments in the commit message.
Progress Updates (Plan File)
Update the plan file at: @/Users/dimfeld/Documents/cc/code4/tasks/522-issue-df-2348-action-definitions-and-permission-settings.plan.md
After each successful iteration (and again at the end of the run), update the plan file's ## Current Progress section:
- Create the section at the end of the file if it does not exist (keep it outside any generated delimiters).
- Update in place: edit or replace outdated text so the section reflects current reality while preserving meaningful history.
- No timestamps anywhere in the section.
- Focus on what changed, why it changed, and what's next. Omit testing/review info, focus on what's useful to remember when starting the next task.
- Only remove information if it no longer applies. For example, decisions from previous tasks should remain unless they have been changed.
- In
### Lessons Learned, capture surprises, gotchas, non-obvious fixes, and what was learned from review feedback or review-fix iterations. Only include lessons that will actually be useful in the future, not things that are just specific only to the work just performed in this plan.
Use this structured template (fill every heading; use "None" when empty):
Current Progress
Current State
- ...
Completed (So Far)
- ...
Remaining
- ...
Next Iteration Guidance
- ...
Decisions / Changes
- ...
Lessons Learned
- Record surprises, unexpected issues, non-obvious solutions, workarounds, or undocumented insights.
- Especially note what you learned while fixing review feedback and why the issue occurred, if the insights are applicable to future tasks and not just this one.
- Update this subsection in place. Keep ongoing lessons that still matter; remove only stale lessons.
- None
Risks / Blockers
- None
Task Context
Below is the original task that needs to be completed through this multi-agent workflow:
---
@/Users/dimfeld/Documents/cc/code4/tasks/522-issue-df-2348-action-definitions-and-permission-settings.plan.md
Project Details:
Action Definitions and Permission Settings
Define the data model and schema for agent actions:
- Create a registry/table of all possible agent actions
- Permission settings per action type:
- Confidence-based: if the action has a confidence score, set a minimum confidence level (low, medium, or high) to auto-approve; require approval below that level
- Always allow: no approval needed
- Require approval: always needs human sign-off
- These settings should be configurable per organization
This is the foundational schema that the rest of the system builds on.
Research
Overview
This plan establishes the foundational data model for agent actions: a code-based registry of action type definitions and a database table for per-organization permission settings that control whether each action type requires human approval, is auto-approved, or uses confidence-based thresholds.
Key Findings
1. Registry Pattern (Code-Based)
The codebase has a well-established pattern for type-safe registries, most notably the Checklist Criteria Registry (modules/checklists/src/criteria/registry.ts). This pattern uses:
- A
Map<string, RegisteredDefinition>keyed by a string type identifier - A factory function (e.g.,
defineChecklistCriteria()) that both defines and auto-registers - Zod schema validation for configuration data
- Type-safe lookup with
getRegistered*(type)functions
Other registries following similar patterns:
- Tool Registry (
libs/agents/src/tools/registry.ts) — for agent tools with category classification - Finish Handler Registry (
modules/checklists/src/finish-handlers/registry.ts) - Webhook Integration Registry (
modules/external-integrations/src/services/incoming-webhooks/registry.ts)
The action type registry should follow this same pattern: definitions live in code, not the database.
2. Existing Agent Framework
The agent framework is already well-developed:
- Agent Tools (
libs/agents/src/tools/types.ts) have acategoryfield with values:read_only,local_write,business_write,control - Business writes already go through a specific execution path via
UserWriteVO(Restate Virtual Object) that serializes writes per user - ToolDefinition includes
paramsSchema(Zod),resultSchema,idempotent,requiresIdempotencyKeyflags - The
ToolRegistryclass hasgetBusinessWriteToolNames()which returns aReadonlySetof business_write tools
The action type registry is decoupled from the tool registry. Not every business write requires an action type (some writes are pre-approved within their flow), and a single action type could potentially involve multiple writes or come from a non-agent source. The action type registry is a separate concept that the agent framework integration (plan 525) will wire into the business write path when appropriate.
3. Database Schema Patterns
Key patterns from the existing schema:
- Organization-scoped tables use
organizationReference()fromlibs/db/src/schema/common.tswith CASCADE delete - Audit fields via
auditFields(createdAt, updatedAt, active) fromcommon.ts - ID generation uses UUIDv7 via
idColumnfromcommon.ts - pgEnum is used for database-level enums (e.g.,
inventoryTypeEnum,salesAccountStatusEnum) - JSONB columns with
$type<T>()are used for typed settings (e.g.,organizations.settings) - Unique indexes commonly use
(organizationId, typeKey)patterns
4. Permission System
Permissions are role-based (libs/auth/src/permissions/):
- Permissions are defined as string IDs in
libs/auth/src/permissions/permissions.ts(170+ permissions) - Organized by
PermissionCategory(e.g.,BUNDLE,TICKETS,ORDER_REQUESTS) - Some permissions imply others (explicit vs internal implications)
- Checked via
checkPermission()or.anyPermission()/.allPermissions()onserviceMiddleware
New permissions will be needed:
- Managing action permission settings (what approval mode each action type uses)
- The actual approval/denial of action instances (covered by plan 524/526)
5. Organization Settings Patterns
Two approaches exist in the codebase:
A. JSONB on organizations table (settingsTypes.ts): Used for simple key-value settings. Good for boolean flags and simple config. Not suitable here because action permission settings are per-action-type and benefit from individual row management.
B. Separate configuration tables: Used for more complex configurations like checklistDefaultAssignees, featureFlags, notificationSettings. These have their own tables with organizationId + key columns.
The per-action-type permission settings fit pattern B — a dedicated table with (organizationId, actionType) as the key.
6. Service Middleware
Services use the serviceMiddleware builder from @libs/service_middleware:
export const myService = serviceMiddleware('domain.action')
.input(z.object({ ... }))
.anyPermission(['some:permission'])
.wrap(async ({ context, input }) => { ... });
Key methods: .input(), .anyPermission(), .allPermissions(), .allowNoUser(), .featureFlag(), .wrap().
ServiceContext provides: db, user, organization, permissions, flags, reportError, restateClient, s3Client, triggerChecklistRefresh.
7. Migration Conventions
- Located in
libs/db/drizzle/ - Named with timestamp + random name (e.g.,
20260309160912_rolling_ptarmigan) - Generated via
pnpm run generate-migrationsinlibs/db - Each has
up.sqlanddown.sql
8. Default Assignee Grouping
The parent plan mentions wanting group-based default assignee assignment (e.g., "all bill-only approvals assigned to group A"). The checklist system already supports typeKey-based default assignees via checklistDefaultAssignees table. Plan 524 will handle the checklist integration, but this plan should ensure action types have a category or group field that can be used for grouping default assignees.
9. Confidence Scores
Confidence scores exist in the codebase but are not standardized:
- Bill-only import has extraction metadata with confidence
- Agent order form processing uses confidence-based decision matrices
- No centralized confidence score type definition exists
The permission settings table needs a confidenceLevel column using a low | medium | high enum, only used when approvalMode = 'confidence_based'. The agent also produces confidence as low | medium | high — no numeric values involved. resolveApprovalMode compares the agent's confidence level against the configured minimum level (low < medium < high) to decide whether approval is needed.
10. Audit Logging
The audit events table (libs/db/src/schema/eventsSchema.ts) records:
eventType,action,objectId,secondaryObjectId,payload(JSONB)userId,organizationId,route,url,traceId
Decision logging (libs/modules_shared/src/decision-logging.ts) should be used when the system decides whether an action needs approval based on the permission settings.
Critical Files Reference
| File | Relevance |
|------|-----------|
| libs/db/src/schema/common.ts | Reusable column definitions (idColumn, organizationReference, auditFields) |
| libs/db/src/schema/settingsTypes.ts | Settings type patterns |
| libs/db/src/schema/eventsSchema.ts | Audit event schema |
| libs/auth/src/permissions/permissions.ts | Permission definitions — add new permissions here |
| libs/auth/src/permissions/get.ts | Permission checking functions |
| libs/agents/src/tools/types.ts | ToolDefinition with category field |
| libs/agents/src/tools/registry.ts | ToolRegistry class |
| modules/checklists/src/criteria/registry.ts | Registry pattern to follow |
| modules/checklists/src/criteria/define.ts | Factory function pattern to follow |
| modules/checklists/src/services/default-assignee-service.ts | Default assignee pattern |
| libs/service_middleware/src/serviceMiddleware.ts | Service middleware builder |
| libs/modules_shared/src/decision-logging.ts | Decision logging for conditional actions |
---
Implementation Guide
Expected Behavior/Outcome
After this plan is complete:
- Action Type Registry: A code-based registry exists where each agent action type is defined with its name, description, category/group, and whether it supports confidence scores. New action types can be added by calling a factory function that auto-registers.
- Permission Settings Table: A database table (
agent_action_permission_settings) stores per-organization permission settings for each action type. Each row specifies an approval mode:always_allow,require_approval, orconfidence_based(with a confidence level).
- Default Settings: Each action type definition includes a default approval mode that applies when no organization-specific override exists.
- Service Functions: Service functions exist to get/set permission settings, resolve the effective approval mode for a given action + organization (considering defaults), and query available action types.
- Permission Gate: A new permission (
agent_actions:manage_settings) controls who can modify action permission settings.
Acceptance Criteria
- [ ] Action type registry exists with factory function for defining new types
- [ ] At least one action type is registered (for the bill-only email metadata update use case from plan 527)
- [ ] Database migration creates
agent_action_permission_settingstable with proper indexes - [ ] Service functions exist:
getActionPermissionSettings,setActionPermissionSettings,resolveApprovalMode - [ ]
resolveApprovalModecorrectly falls back to the action type's default when no org-specific setting exists - [ ] Permission
agent_actions:manage_settingsis defined and required for modifying settings - [ ] Decision logging is used when resolving approval mode
- [ ] All new code paths are covered by integration tests
- [ ] pgEnums
agent_action_approval_modeandagent_action_confidence_levelare created - [ ] Settings UI page exists at
/settings/automation/agent-actionsshowing all action types grouped by category - [ ] Settings UI allows changing approval mode and confidence level per action type, with reset-to-default
Dependencies & Constraints
- Dependencies: Uses existing patterns from checklist criteria registry, service middleware, permission system
- Technical Constraints: Must be organization-scoped. Must not break existing agent tool registry. Action type keys must be stable strings that can be referenced by other plans (523, 524, 525).
- Downstream Consumers: Plans 523 (action instances), 524 (checklist integration), 525 (agent framework integration) all depend on the action type registry and permission settings from this plan.
Step-by-Step Implementation
Step 1: Define the Action Type Registry Types
Create a new module modules/agent_actions/ following the standard module structure. Start with the type definitions.
Create modules/agent_actions/src/types/action-types.ts:
- Define
AgentActionTypeDefinitioninterface: type: string— unique key (e.g.,'bill_only.email_metadata_update')name: string— human-readable namedescription: string— what this action doescategory: AgentActionCategory— grouping key used for both default assignee grouping and determining which settings page the action configurations appear in. Defined as a TypeScript union type (e.g.,'bill_only' | 'order_requests') for consistency, with new values added as new action types emerge.supportsConfidence: boolean— whether this action type provides confidence scoresdefaultApprovalMode: AgentActionApprovalMode— default when no org override existsdefaultConfidenceLevel?: AgentActionConfidenceLevel— default confidence level if mode is confidence-based ('low' | 'medium' | 'high')dataSchema: ZodType— Zod schema describing the action's proposed write payload (editable by approvers during approval)contextSchema?: ZodType— optional Zod schema for type-specific context fields that must be provided when creating an instance (e.g.,orderId,locationIdfor bill-only actions). Plan 523's action instance table will also have common context fields (likesourceEmailId,sourceThreadId) available to all action types.
- Define
AgentActionApprovalModeas a union type:'always_allow' | 'require_approval' | 'confidence_based'
- Define
AgentActionConfidenceLevelas a union type:'low' | 'medium' | 'high'. Both the agent's output and the org setting use this same enum — no numeric values.resolveApprovalModecompares the agent's confidence level against the configured minimum (low < medium < high) to decide whether approval is needed.
- Define
AgentActionCategoryas a TypeScript union type: initially'bill_only', with new values added as action types are created. This type ensures consistency across action definitions and is used by both the default assignee system (plan 524) and the settings UI to group actions.
Reference the checklist criteria types at modules/checklists/src/criteria/types.ts for structural guidance.
Step 2: Create the Action Type Registry
Create modules/agent_actions/src/registry/registry.ts:
- Follow the pattern from
modules/checklists/src/criteria/registry.ts - Use a
Map<string, AgentActionTypeDefinition>for storage - Export functions:
registerAgentActionType(definition)— registers a type, throws on duplicategetAgentActionType(type)— returns definition or undefinedgetAllAgentActionTypes()— returns all registered typesgetAgentActionTypesByCategory(category)— returns types filtered by category
Create modules/agent_actions/src/registry/define.ts:
- Factory function
defineAgentActionType(definition)that validates and auto-registers - Similar to
defineChecklistCriteria()pattern
Step 3: Register the First Action Type
Create modules/agent_actions/src/action-types/bill-only-email-metadata-update.ts:
- Use
defineAgentActionType()to register the first action type - Type key:
'bill_only.email_metadata_update' - Category:
'bill_only' supportsConfidence: truedefaultApprovalMode: 'confidence_based'defaultConfidenceLevel: 'high'- Data schema: Define a Zod schema for the metadata fields that can be updated (PO number, etc.)
- Context schema: Define a Zod schema for required context (e.g.,
orderId,locationId)
This provides a concrete test case and validates the registry design.
Step 4: Create Database Schema
Add to libs/db/src/schema/ — create agentActionSchema.ts:
Create the pgEnums:
export const agentActionApprovalModeEnum = pgEnum('agent_action_approval_mode', [
'always_allow',
'require_approval',
'confidence_based',
]);
export const agentActionConfidenceLevelEnum = pgEnum('agent_action_confidence_level', [
'low',
'medium',
'high',
]);
Create the permission settings table:
export const agentActionPermissionSettings = pgTable('agent_action_permission_settings', {
...idColumn,
...organizationReference(organizations),
actionType: text('action_type').notNull(),
approvalMode: agentActionApprovalModeEnum('approval_mode').notNull(),
confidenceLevel: agentActionConfidenceLevelEnum('confidence_level'), // nullable, only used when approvalMode = 'confidence_based'
...auditFields,
}, (table) => [
uniqueIndex('agent_action_permission_settings_org_type_idx')
.on(table.organizationId, table.actionType),
]);
Add relations in the same file linking to organizations.
Export from libs/db/src/schema/index.ts.
Step 5: Generate Migration
Run pnpm run generate-migrations in libs/db to generate the migration SQL. Verify the generated SQL creates the enum and table correctly.
Step 6: Add Permission Definition and Feature Flag
Edit libs/auth/src/permissions/permissions.ts:
- Add a new
PermissionCategory:AGENT_ACTIONS - Add permission:
'agent_actions:manage_settings'— allows modifying action permission settings for the organization - Add to the appropriate standard roles (likely Administrator)
Edit libs/auth/src/featureflags/flags.ts:
- Add feature flag:
agent_actionswithdefault: false,use: 'access',active: true - This flag gates only the settings UI, not the backend services or registry (so that the agent framework can use
resolveApprovalModeregardless of flag state)
Step 7: Create Service Functions
Create modules/agent_actions/src/services/permission-settings-service.ts:
Using serviceMiddleware pattern:
getActionPermissionSettings— Fetches all permission settings for an organization
- Uses ServiceContext organization
- Permission: read-only, any authenticated user
- Returns: array of settings rows joined with action type metadata from registry
setActionPermissionSetting— Upserts a single action type's permission setting
- Input:
{ actionType, approvalMode, confidenceLevel? } - Permission:
agent_actions:manage_settings - Validates: actionType exists in registry, confidenceLevel required iff mode is
confidence_based, must be a validAgentActionConfidenceLevel - Uses
ON CONFLICT (organizationId, actionType) DO UPDATE - Logs audit event
resolveApprovalMode— Determines whether an action needs approval
- Input:
{ actionType, agentConfidence?: AgentActionConfidenceLevel }—agentConfidenceis required when the action type hassupportsConfidence: true - Uses ServiceContext organization (no explicit org ID needed)
- Uses
.allowNoUser()since this will be called from agent/workflow contexts without a user session - Looks up org-specific setting; falls back to registry default
- For
confidence_basedmode: comparesagentConfidenceagainst the configured minimum level (low < medium < high). If the agent's confidence meets or exceeds the threshold, no approval is needed. - Uses
logDecisionto record the resolution (both the setting used and the outcome) - Returns:
{ needsApproval: boolean, approvalMode, confidenceLevel?, source: 'organization' | 'default' }
deleteActionPermissionSetting— Removes org-specific override, reverting to default
- Input:
{ actionType } - Permission:
agent_actions:manage_settings - Logs audit event
Step 8: Create Module Package Structure
Set up the standard module package:
modules/agent_actions/package.json— with exports map forservices,types, etc.modules/agent_actions/src/index.ts— barrel exportmodules/agent_actions/tsconfig.jsonmodules/agent_actions/vitest.config.ts(if needed, check other modules)
Reference modules/inventory/ or modules/organizations/ for the standard structure.
Run pnpm install after creating the package to ensure monorepo linking.
Step 9: Write Integration Tests
Create modules/agent_actions/src/services/permission-settings-service.integration.test.ts:
Using PostgresTestEnvironment:
- Test
setActionPermissionSetting:
- Sets a new permission setting and verifies it's stored
- Updates an existing setting and verifies the change
- Rejects invalid action types (not in registry)
- Rejects confidence_based mode without a confidence level
- Rejects invalid confidence level values
- Requires
agent_actions:manage_settingspermission
- Test
getActionPermissionSettings:
- Returns all settings for the organization
- Returns empty array when no settings exist
- Includes action type metadata from registry
- Test
resolveApprovalMode:
- Returns org-specific setting when it exists
- Falls back to registry default when no org setting exists
- For
always_allow: returnsneedsApproval: false - For
require_approval: returnsneedsApproval: true - For
confidence_basedwith agent confidence >= configured level: returnsneedsApproval: false - For
confidence_basedwith agent confidence < configured level: returnsneedsApproval: true - Decision logging is called in all cases
- Test
deleteActionPermissionSetting:
- Removes the setting
resolveApprovalModereturns default after deletion
Create modules/agent_actions/src/registry/registry.test.ts:
Unit tests for the registry:
- Registers and retrieves action types
- Throws on duplicate registration
- Filters by category
- Returns undefined for unknown types
Step 10: Settings UI — Add Navigation and Route
Add agent action settings to the existing settings navigation and create the route structure.
Edit apps/inbox/src/routes/settings/+layout.svelte:
- Add a new nav item under the Automation section for "Agent Actions" (or integrate into existing automation pages by category)
- Gate visibility behind
agent_actions:manage_settingspermission ANDagent_actionsfeature flag - Link to
/settings/automation/agent-actions
Create apps/inbox/src/routes/settings/automation/agent-actions/:
+page.server.ts— Load function that:- Requires
agent_actionsfeature flag andagent_actions:manage_settingspermission - Calls
getActionPermissionSettings()to get org-specific overrides - Calls
getAllAgentActionTypes()from the registry to get all available action types with their defaults - Returns both so the UI can show current effective settings for each action type
- Adds breadcrumb
Step 11: Settings UI — Remote Functions and Schema
Create apps/inbox/src/routes/settings/automation/agent-actions/agent-actions.types.ts:
- Zod schema for the settings form:
actionType(string),approvalMode(enum),confidenceLevel(optional enum)
Create apps/inbox/src/routes/settings/automation/agent-actions/agent-actions.remote.ts:
form()handler for updating a single action type's permission setting- Wraps with
remoteGuard().anyPermission(['agent_actions:manage_settings']).wrapForm() - Calls
setActionPermissionSetting()service - Returns success message via
withFormMeta() command()handler for resetting to default (callsdeleteActionPermissionSetting())
Step 12: Settings UI — Page Component
Create apps/inbox/src/routes/settings/automation/agent-actions/+page.svelte:
Following the existing automation settings page patterns:
- Use
PageHeaderwith title "Agent Action Settings" - Group action types by
categoryusingCard.Rootper category - For each action type within a category, show:
- Action name and description
- Current approval mode (dropdown/select: Always Allow, Require Approval, Confidence-Based)
- If confidence-based: confidence level selector (Low, Medium, High)
- Whether the current setting is the default or an org override (visual indicator)
- Reset-to-default button when an override exists
- Use
FormManagerper action type row (each is an independent form) - Wrap in
<fieldset disabled={!data.canManageSettings}>for read-only when user lacks permission - Show
Form.FormLevelErrorsandForm.FormMessagefor feedback
Step 13: Verify Quality
Run from the module directory:
pnpm test— all tests passpnpm check— TypeScript compilespnpm run lint— no lint errorsturbo run semgrep— no semgrep violations
Implementation Notes
- Recommended Approach: Code-based registry for action type definitions (like checklist criteria) + database table for per-org permission settings. This gives type safety for definitions while allowing runtime configuration.
- Potential Gotchas:
- The registry must be populated before any service functions reference it. Ensure auto-registration happens on module load (follow checklist criteria pattern where imports trigger registration).
- The
confidenceLevelcolumn uses a pgEnum (agent_action_confidence_level). Both the org setting and the agent's output use the samelow | medium | highenum — no numeric values anywhere. - When adding the new schema file, ensure it's exported from
libs/db/src/schema/index.tsso Drizzle picks it up for migration generation. - The
actionTypecolumn in the settings table is atextreferencing the registry key, not a foreign key — this is intentional since definitions are code-based. - Why not a database table for action type definitions?: Action types are tightly coupled to code (they have Zod schemas, execution logic). A code-based registry ensures type safety and avoids sync issues. The database table is only for the configurable parts (approval settings per org).
Current Plan Context
Current Plan File: tasks/522-issue-df-2348-action-definitions-and-permission-settings.plan.md
Current Plan Title: Action definitions and permission settings
Parent Plan Context
Parent Plan File: tasks/521-issue-df-2346-agent-actions-and-approvals-system.plan.md
Parent Plan: Agent actions and approvals system (ID: 521)
Parent Details: We should be able to define a big list of actions that agents can do. There should be permission settings around these actions, which can be based on the confidence if the action has a confidence and otherwise is just require approval or always allow. Actions that require approval should be able to be approved or denied or, when applicable, have the data edited. Approval should also have an optional note.
Actions that require approval should have related checklist items so that people can see what is waiting for approval. These checklist items should be individually and have default assignees, like the current system allows. We should also have a way to assign groups of them to have defaults. For example all bill-only approvals may be assigned to a certain group while all order request approvals might be assigned to a different group or something like that.
The table of the actual instances of actions should record:
- the decision and the notes on the decision
- the original and edited data
We'll also need to have links back to things such as the source email or other information, depending on the item type. The UI for handling these actions should show all the related data, for example showing the content and relevant addresses and subject of the email.
Integrate this into the agent framework so that whenever it tries to do a business write that links into the agent action that is appropriate. If the action requires approval then the agent will stall and wait for the approval. The framework should make it easy to resume and either finish the write or handle the decline and then continue in whatever way is appropriate, whether that's an actual agent model continuing or just a state machine handling it and going to a different state.
The first instance of this will be for a simple agent that will parse an email looking for updated metadata for bill-only orders and then try to trigger a business write to do the updates.
I think business writes may always be linked to users right now; we will want to remove that requirement if so.
Sibling Plans (Same Parent)
These are other plans that are part of the same parent plan. Reference them for additional context about the overall project structure.
Pending Sibling Plans:
- Action instances data model (File: tasks/523-issue-df-2349-action-instances-data-model.plan.md)
- Approval workflow with checklist integration (File: tasks/524-issue-df-2350-approval-workflow-with-checklist-integration.plan.md)
- Agent framework integration for actions and approvals (File: tasks/525-issue-df-2351-agent-framework-integration-for-actions-and-approvals.plan.md)
- Agent Action Approval UI (File: tasks/526-issue-df-2352-agent-action-approval-ui.plan.md)
- First agent: bill-only order email metadata updates (File: tasks/527-issue-df-2353-first-agent-bill-only-order-email-metadata-updates.plan.md)
Remaining Tasks
Please select and complete a logical subset of the following incomplete tasks that makes sense to work on together.
IMPORTANT: It's better to choose a small number of closely related tasks that form an atomic unit than to take on too many at once. Focus on what can be completed well in a single iteration.
Available tasks:
Task 1: Create module package structure
Description: Set up the modules/agent_actions/ module following standard module structure. Create package.json with exports map (services, types, registry), src/index.ts barrel export, tsconfig.json, and vitest.config.ts. Reference modules/inventory/ or modules/organizations/ for the standard structure. Run pnpm install after to ensure monorepo linking. This should be done first so subsequent files have a home.
Task 2: Define action type registry types
Description: Create modules/agent_actions/src/types/action-types.ts with:
AgentActionApprovalModeunion type:'always_allow' | 'require_approval' | 'confidence_based'AgentActionConfidenceLevelunion type:'low' | 'medium' | 'high'(used by both agent output and org settings — no numeric values)AgentActionCategoryunion type: initially'bill_only', extended as new action types are addedAgentActionTypeDefinitioninterface with fields:type(unique key),name,description,category: AgentActionCategory,supportsConfidence: boolean,defaultApprovalMode,defaultConfidenceLevel?,dataSchema: ZodType(proposed write payload, editable by approvers),contextSchema?: ZodType(type-specific context fields for instances, e.g. orderId, locationId)
Reference modules/checklists/src/criteria/types.ts for structural guidance.
Task 3: Create the action type registry
Description: Create modules/agent_actions/src/registry/registry.ts following the pattern from modules/checklists/src/criteria/registry.ts:
- Use a
Map<string, AgentActionTypeDefinition>for storage - Export functions:
registerAgentActionType(definition)(throws on duplicate),getAgentActionType(type),getAllAgentActionTypes(),getAgentActionTypesByCategory(category)
Create modules/agent_actions/src/registry/define.ts:
- Factory function
defineAgentActionType(definition)that validates and auto-registers, similar todefineChecklistCriteria()pattern.
Task 4: Register the first action type (bill-only email metadata update)
Description: Create modules/agent_actions/src/action-types/bill-only-email-metadata-update.ts using defineAgentActionType():
- Type key:
'bill_only.email_metadata_update' - Category:
'bill_only' supportsConfidence: truedefaultApprovalMode: 'confidence_based'defaultConfidenceLevel: 'high'dataSchema: Zod schema for metadata fields that can be updated (PO number, etc.)contextSchema: Zod schema for required context (e.g.,orderId,locationId)
This provides a concrete test case and validates the registry design.
Task 5: Create database schema for permission settings
Description: Create libs/db/src/schema/agentActionSchema.ts with:
agentActionApprovalModeEnumpgEnum:['always_allow', 'require_approval', 'confidence_based']agentActionConfidenceLevelEnumpgEnum:['low', 'medium', 'high']agentActionPermissionSettingstable:idColumn,organizationReference(organizations),actionType: text,approvalMode: agentActionApprovalModeEnum,confidenceLevel: agentActionConfidenceLevelEnum(nullable),auditFields- Unique index on
(organizationId, actionType) - Relations linking to
organizations
Export from libs/db/src/schema/index.ts. Then run pnpm run generate-migrations in libs/db and verify the generated SQL.
Task 6: Add permission definition and feature flag
Description: Edit libs/auth/src/permissions/permissions.ts:
- Add
PermissionCategory.AGENT_ACTIONS - Add permission
'agent_actions:manage_settings'for modifying action permission settings - Add to appropriate standard roles (Administrator)
Edit libs/auth/src/featureflags/flags.ts:
- Add feature flag
agent_actionswithdefault: false,use: 'access',active: true - This flag gates only the settings UI, not backend services or registry
Task 7: Create service functions for permission settings
Description: Create modules/agent_actions/src/services/permission-settings-service.ts using serviceMiddleware pattern:
getActionPermissionSettings— Fetches all permission settings for the ServiceContext organization. Read-only, any authenticated user. Returns settings rows joined with action type metadata from registry.
setActionPermissionSetting— Upserts a single action type's setting. Input:{ actionType, approvalMode, confidenceLevel? }. Permission:agent_actions:manage_settings. Validates actionType exists in registry, confidenceLevel required iffconfidence_based. UsesON CONFLICT DO UPDATE. Logs audit event.
resolveApprovalMode— Determines whether an action needs approval. Input:{ actionType, agentConfidence?: AgentActionConfidenceLevel }. Uses.allowNoUser()for agent/workflow contexts. Looks up org-specific setting, falls back to registry default. Forconfidence_based: compares agentConfidence >= configured level (low < medium < high). UseslogDecision. Returns{ needsApproval: boolean, approvalMode, confidenceLevel?, source: 'organization' | 'default' }.
deleteActionPermissionSetting— Removes org-specific override. Permission:agent_actions:manage_settings. Logs audit event.
Task 8: Write registry unit tests
Description: Create modules/agent_actions/src/registry/registry.test.ts with unit tests:
- Registers and retrieves action types
- Throws on duplicate registration
- Filters by category correctly
- Returns undefined for unknown types
getAllAgentActionTypes()returns all registered types
Task 9: Write service integration tests
Description: Create modules/agent_actions/src/services/permission-settings-service.integration.test.ts using PostgresTestEnvironment:
setActionPermissionSetting: sets new setting, updates existing, rejects invalid action types, rejects confidence_based without confidence level, requires permissiongetActionPermissionSettings: returns all settings, returns empty when none exist, includes action type metadataresolveApprovalMode: returns org-specific when exists, falls back to default,always_allow→ needsApproval false,require_approval→ needsApproval true,confidence_basedwith agent >= configured → needsApproval false,confidence_basedwith agent < configured → needsApproval true, decision logging called in all casesdeleteActionPermissionSetting: removes setting, resolveApprovalMode returns default after deletion
Task 10: Settings UI — Add navigation and route
Description: Edit apps/inbox/src/routes/settings/+layout.svelte:
- Add nav item under Automation section for 'Agent Actions'
- Gate visibility behind
agent_actions:manage_settingspermission ANDagent_actionsfeature flag - Link to
/settings/automation/agent-actions
Create apps/inbox/src/routes/settings/automation/agent-actions/+page.server.ts:
- Requires
agent_actionsfeature flag andagent_actions:manage_settingspermission - Calls
getActionPermissionSettings()for org-specific overrides - Calls
getAllAgentActionTypes()from registry for all available types with defaults - Returns both so UI can show current effective settings
- Adds breadcrumb
Task 11: Settings UI — Remote functions and schema
Description: Create apps/inbox/src/routes/settings/automation/agent-actions/agent-actions.types.ts:
- Zod schema for settings form:
actionType(string),approvalMode(enum),confidenceLevel(optional enum)
Create apps/inbox/src/routes/settings/automation/agent-actions/agent-actions.remote.ts:
form()handler for updating a single action type's setting, wrapped withremoteGuard().anyPermission(['agent_actions:manage_settings']).wrapForm(), callssetActionPermissionSetting(), returns success viawithFormMeta()command()handler for resetting to default, callsdeleteActionPermissionSetting()
Task 12: Settings UI — Page component
Description: Create apps/inbox/src/routes/settings/automation/agent-actions/+page.svelte following existing automation settings patterns:
PageHeaderwith title 'Agent Action Settings'- Group action types by
categoryusingCard.Rootper category - Per action type: name, description, approval mode dropdown (Always Allow, Require Approval, Confidence-Based), confidence level selector (Low/Medium/High, shown only when confidence-based), default/override indicator, reset-to-default button when override exists
FormManagerper action type row (independent forms)<fieldset disabled={!data.canManageSettings}>for read-only without permissionForm.FormLevelErrorsandForm.FormMessagefor feedback
Task 13: Verify quality
Description: Run from the module directory and repo root:
cd modules/agent_actions && pnpm test— all tests passpnpm check— TypeScript compilespnpm run lint— no lint errorsturbo run semgrep— no semgrep violationsturbo run format— code formatted
Plan File
- @tasks/522-issue-df-2348-action-definitions-and-permission-settings.plan.md: This is the plan file you can reference if you need to check the plan again.
Execution Guidelines
Understand the Codebase Context
Before implementing changes:
- Examine existing patterns and conventions in the codebase
- Look for similar implementations or components that can serve as examples
- Understand the project structure and where your changes fit
- Review any relevant tests to understand expected behavior
Track Your Progress
Create a TODO list to organize your work:
- Break down the task into specific, actionable items
- Include items for code changes, tests, and verification
- Track which items are completed as you progress
- Update the list if you discover additional work needed
- Use the TodoWrite tool to maintain your TODO list.
Follow Best Practices
Ensure your implementation:
- Matches the existing code style and patterns
- Uses the same libraries and utilities already in the codebase
- Follows the project's naming conventions
- Maintains consistent error handling patterns
- Includes appropriate type annotations
Verify Your Work
After implementing changes:
- Run the build command to ensure compilation succeeds
- Execute tests to verify functionality
- Run linting tools to check code quality
- Fix any issues before considering the task complete
Self-Review Checklist
Before marking the task as done, verify:
- [ ] Changes align with the plan's goals and requirements
- [ ] Code follows existing patterns in the codebase
- [ ] All tests pass successfully
- [ ] Linting checks pass without errors
- [ ] No unnecessary files or debug code included
- [ ] Changes are focused and don't include modifications to unrelated parts of the code
Remember: Quality is more important than speed. Take time to understand the codebase and verify your changes work correctly within the existing system.
</details>
This issue has 4 comments on GitHub. Read the full discussion on GitHub ↗