CrowdRelay Autopilot should remember deadlines, not run the band
ViryaOS got useful once I made its automation accountable: deterministic decisions, bounded authority, execution receipts and a single view of the exceptions that need a person.
- Engineering
- Rust
- Architecture
- Automation
There's a tempting version of band automation where an AI agent gets Gmail, Calendar, social media and a vague objective such as “get us more shows”.
I built almost the opposite.
The current CrowdRelay Autopilot is deliberately deterministic. It doesn't need a personality, a browser session or permission to improvise. It needs good facts, explicit authority and a receipt after every side effect.
Seven programs, one authority gate
Internally the code is split into bounded contexts, but the team doesn't need to think in crate names. From the product side there are seven programs: release, fan growth, press, opportunities, commerce, patronage/endorsement and funding.
Each program reads facts CrowdRelay already owns and produces a domain decision. The decision then passes through a shared authority gate.
A context can observe, recommend, require approval or execute inside bounded policy. Confidence thresholds and daily quotas are explicit. A global kill switch can stop autonomous execution without deleting the facts that produced the decision.
What bounded autonomy means
The phrase “autonomous agent” often hides the most important question: autonomous to do what? ViryaOS makes that question concrete.
A reversible calendar upsert is different from signing a contract. A free, high-confidence, non-exclusive application is different from paying an entry fee. A first-party fan reminder is different from cold outreach to an unverified address.
The domain that owns the action also owns its limits. The shared autonomy vocabulary doesn't know ticket economics, outreach cooldowns or funding rules; it only applies the authority and confidence gate after the domain has made its decision.
That keeps the shared part small and useful. The alternative is a universal policy engine that knows everything badly.
Keeping n8n replaceable
Provider execution sits outside the decision core on purpose.
CrowdRelay may ask for calendar.upsert, outreach.send or funding.package. The executor binds that capability to a real provider and reports accepted, executing, succeeded or failed.
If Gmail is replaced one day, the outreach domain shouldn't care. If Discord disappears, “notify the operator” shouldn't become a new business rule.
The executor also advertises which capabilities it actually has. A release manifest and heartbeat stop the backend from assuming a workflow exists just because it existed last week.
Counting only provider-confirmed results
A queued job isn't a sent email. An HTTP 200 from an internal bridge isn't a provider outcome. A draft isn't outreach. A checkout redirect isn't payment. ViryaOS keeps those distinctions all the way through.
decisionauthorityactionexecution claimproviderreceiptmeasurementnext policy decisionFor provider operations without native idempotency, a durable pre-send claim stops a retry from accidentally duplicating the side effect. Provider references such as Gmail thread IDs come back into the execution ledger, so inbound events can be correlated to the original action without n8n owning a second map.
Showing exceptions in the UI
An automation system can work well and still fail as a product if the team has to stare at its internals all day.
So Virya Signal treats ViryaOS as a Chief of Staff. It surfaces what needs a person: approvals, operational failures, measured regressions, show readiness and deadlines.
The Deadline Radar is a good example. Approval expiry and opportunity deadlines already existed in authoritative tables. Instead of building a new tasks service, Signal gets one read model that turns those dates into an ordered attention list.
There's no duplicate state, no polling loop just to feel “real time”, and no second place where a deadline can disagree with the first.
Clear ownership
What surprised me is that making the autopilot do more didn't require a more agentic architecture. It required removing ambiguity about who owns what.
CrowdRelay owns durable state and decisions. PostgreSQL owns persistence. n8n and providers execute. Signal presents exceptions. AI may enrich language, but it doesn't get authority. OpenAPI and signed event contracts are the compatibility boundary; internal Rust modules remain implementation details.
That's the version of an autopilot I trust around a real band. It knows exactly what it's allowed to do, remembers what actually happened, and only bothers a human when the next decision needs one.
Push delivery health
Push notifications are no longer a hidden transport detail. CrowdRelay exposes the same operational queue shape for push as for the outbox and provider deliveries: pending, in-flight, failed, delivered in the last 24 hours, and age of the oldest pending item. Those numbers also exist as Prometheus metrics.
The Virya web control plane and the Virya Signal operator view consume that state instead of inventing a second health model. The public push configuration separately reports whether Android FCM and Web Push are actually configured, while push_delivery_enabled remains an explicit kill switch.
It sounds like UI plumbing, but it closes a gap: a communication capability isn't “working” just because an endpoint accepted a subscription. Operators can now see whether delivery is moving.
Splitting modules without moving boundaries
The codebase also got less monolithic without getting more abstract. Large Rust orchestration modules were split into narrow implementation chunks, and the dependency direction stayed the same: pure domain policy works on typed objects, application code builds decisions and coordinates ports, infrastructure owns SQL and provider adapters, and API/worker layers expose or execute the use cases.
A source-size ratchet now keeps production Rust modules below the agreed ceiling, so that doesn't depend on discipline after the next feature lands. The aim is to make it hard for persistence, transport and policy to quietly grow back into one controller.