Develop scheduled tasks in NocoBase 3 that business administrators need to view and track through the application UI. Define schedules in code, register the target a schedule points at, integrate execution status, and report completion. Do not use Scheduler to manage tasks that do not need UI visibility.
npx skills add https://github.com/nocobase/nocobase --skill nocobase-app-plugin-scheduler
Use the installed version's public exports, without importing plugin internals. The application owns business logic, schedule declarations, Providers, permissions, and deployment timing. Scheduler owns scheduling projections, trigger history, and execution state. The plugin's skills/ directory is the source of truth; do not edit the synchronized application copy under .agents/skills/.
The primary reason to define tasks through Scheduler is UI observability for business administrators. Developers define schedules and execution logic in code. Business administrators use the task list and detail pages the application builds on the Scheduler API to view schedules, track individual executions, and enable or disable tasks when authorized.
Tasks that do not need to be viewed and tracked through the UI must not be managed by the Scheduler plugin. Give recurring ones a ScheduleExecutor of their own from the application's jobs service (jobExecutorServiceToken in @nocobase/app-server/jobs), and one-off background work a JobExecutor; the application development Skill describes both. For administrator-visible tasks, deliver Client registration, access permissions, meaningful task names, and accurate final execution status together; successful server-side dispatch alone is incomplete.
After deciding to use Scheduler, choose according to business complexity:
| Scenario | Choice | Implementation boundary |
| ----------------------------------------------------------------------------------------- | --------------- | -------------------------------------------------------------------------------------------------------- |
| Periodic cleanup, cache refresh, a single report, or one business Service call | Own target type | Short operations may complete directly; hand lengthy work to a JobExecutor |
| A simple operation that happens hourly | Own target type | Cron alone is not a reason to introduce a heavier execution system |
| Immediate asynchronous execution | JobExecutor | No Cron Schedule is needed |
| A one-time delay, such as ten minutes after a request | Queue delay | No Cron Schedule is needed; JobExecutor has no delay |
| Another execution system with its own references, status queries, and completion protocol | Own target type | The same registerTarget() call, with inspect() and completion reporting for work that finishes later |
Every schedule points at a registered target; registerTarget() is the target extension surface, and there is no built-in target type. A target does not guarantee exactly-once external business effects; design business idempotency.
JobExecutor, report completion, or diagnose a historical occurrence after retargeting, read Target Extensions and Execution Protocol.jobs configuration (a redis adapter for more than one instance; memory serves one process) and JobExecutorServiceProvider composition and target availability, then choose or register the target type.schedulerServiceToken.defineSchedule(definition) with an application-wide stable key from that Provider's register()/boot().target.config.--finalize in production only when the complete manifest is visible.Schedules are defined in code. There is no management API for creating or editing Cron definitions, but the UI and API support enabling and disabling tasks. Do not modify schedule_definitions, schedule_occurrences, or the schedule backend's rules (BullMQ job schedulers, or the memory adapter's state file) directly, and do not add jobs under Scheduler's @nocobase/app-plugin-scheduler scope.
Take nocobase/nocobase-app-plugin-scheduler from the repository into ~/.claude/skills for personal
use, or into .claude/skills inside a project.
The agent identifies a skill by the name field in its header. Two skills with the
same name cannot sit side by side — one of them will be ignored.