Concurrency control — multiple instances of the same agent
- Dominant language
- Rust
- Stars
- 3
- Forks
- 1
- Avg merge
- 4h 50m
- Merged PRs (30d)
- 1
Description
Today an agent runs at most once at a time per `(agent, schedule)`. That is the right default for cron-style work. But some agents are stateless processors — say, a fan-out worker that pulls from a queue — where running 4 in parallel is exactly what you want.
There is no knob to express that.
## Proposal
A new `concurrency` field on `[[schedules]]` (default 1, preserving today's behavior):
```toml
[[schedules]]
id = "worker"
type = "interval"
interval_minutes = 1
concurrency = 4 # up to 4 simultaneous instances
```
When the schedule fires and N instances are already running where N < concurrency, the daemon spawns another. If N == concurrency, the fire is skipped (logged as `concurrency_capped`, audit event emitted).
Each instance gets a unique heartbeat slug (e.g. `worker-0`, `worker-1`) so state files don't collide.
## Acceptance criteria
- [ ] `concurrency = 1` (default) preserves today's behavior bit-for-bit.
- [ ] `concurrency > 1` allows parallel instances with separate heartbeats.
- [ ] Hitting the cap emits an audit event and skips the fire (not queues).
- [ ] `dotagent status` and `dotagent why` reflect "N of M instances running".
- [ ] [`agent-spec.md`](docs/reference/agent-spec.md) updated.
## Where to start
- `crates/dotagent-core/src/manifest.rs` — schema.
- `crates/dotagent/src/commands/daemon.rs` — tick loop where the spawn decision happens.
- `crates/dotagent-state/src/lib.rs` — slug generation.
## Non-goals
- Distributed coordination across machines. Single-host only.
- Work-queue semantics. dotagent stays a scheduler, not a queue runner.
Contributor guide
Research direction
Start by reading the schema in crates/dotagent-core/src/manifest.rs, then trace the spawn decision in crates/dotagent/src/commands/daemon.rs and slug generation in crates/dotagent-state/src/lib.rs. Done means the default remains unchanged, parallel instances have separate heartbeats, capped fires are audited and skipped, status and why show N of M, and docs/reference/agent-spec.md is updated.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- rust
- Domain
- backend
- Issue type
- Feature
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Quiet
- Clarity
- Clearly specified
- Newbie friendliness
- 68/100