Status: Implemented Context: ix-json plugin needs per-glyph polling schedules created at runtime, not just at init
Plugins can only announce Pulse schedules during Initialize via GetSchedules(). This works for static schedules known at startup, but fails when schedules are user-driven:
Currently the ix-json plugin works around this with internal goroutine tickers that enqueue one-shot Pulse jobs. This works but bypasses Pulse's schedule infrastructure — no visibility in the Pulse panel, no persistence across restarts, no state management.
Expose schedule.Store operations to gRPC plugins through a new service, following the same pattern as ATSStoreService and QueueService.
service ScheduleService {
rpc CreateSchedule(CreateScheduleRequest) returns (CreateScheduleResponse);
rpc PauseSchedule(PauseScheduleRequest) returns (PauseScheduleResponse);
rpc ResumeSchedule(ResumeScheduleRequest) returns (ResumeScheduleResponse);
rpc DeleteSchedule(DeleteScheduleRequest) returns (DeleteScheduleResponse);
rpc GetSchedule(GetScheduleRequest) returns (GetScheduleResponse);
}
plugin/grpc/protocol/schedule.proto — service + messagesplugin/grpc/schedule_server.go — server wrapping schedule.Storeplugin/grpc/remote_schedule.go — client implementing plugin-side interfaceplugin/grpc/services_manager.go — start ScheduleService, expose endpointplugin/grpc/protocol/domain.proto — add schedule_endpoint to InitializeRequestplugin/grpc/remote_services.go — add schedule client to RemoteServiceRegistryplugin/services.go — add Schedule() ScheduleService to ServiceRegistrytype ScheduleService interface {
Create(handlerName string, intervalSecs int, payload []byte, metadata map[string]string) (scheduleID string, err error)
Pause(scheduleID string) error
Resume(scheduleID string) error
Delete(scheduleID string) error
}
Activate clicks:
id, err := p.services.Schedule().Create("ix-json.poll", intervalSecs, payload, metadata)
// Store schedule ID in glyph's attestation for later pause/delete
Pause clicks:
err := p.services.Schedule().Pause(scheduleID)
The goroutine ticker, startPoller, stopPoller, and enqueuePollJob all get deleted. Handler registration via GetHandlerNames stays — Pulse still needs to know where to route ix-json.poll jobs.
Any plugin can create recurring Pulse schedules at runtime based on user actions. The pattern applies beyond ix-json — any plugin with user-configured periodic work benefits.