pzza.works

Building Scheduled Workflows in Astreus

Berke (pzzaworks)Berke (pzzaworks)

December 1st, 2025

Astreus lets you build time-based automated workflows out of plain schedule strings and explicit dependencies between tasks. In this guide I walk through creating workflows that run on their own, on your schedule.

Quick Start

Get started by cloning the example repository or installing the package:

Bash
git clone https://github.com/astreus-ai/astreus cd scheduled-workflows npm install

Or install directly:

Bash
npm install @astreus-ai/astreus

Create a .env file with your configuration:

OPENAI_API_KEY=sk-your-openai-api-key-here
DB_URL=sqlite://./astreus.db
NODE_ENV=development

The database persists workflow state, so tasks pick up where they left off after a restart.

Creating Your First Agent

Every workflow starts with an agent that handles the AI operations:

TypeScript
const agent = await Agent.create({ name: 'ContentAgent', model: 'gpt-4o', systemPrompt: 'You are a content creation specialist.' });

The agent wraps the AI model and its behavior. You can create several agents with different capabilities and give each one a different kind of task.

Building a Workflow Graph

A workflow is a graph of nodes and the dependencies between them:

TypeScript
const graph = new Graph({ name: 'Quick Test Pipeline', description: 'Test automated workflow with seconds interval', maxConcurrency: 2 }, agent);

The graph owns the execution order, the concurrency limit and the task dependencies. Setting maxConcurrency keeps the workflow from blowing through your API limits or system resources.

Adding Scheduled Tasks

Add task nodes with schedules and dependencies:

TypeScript
const researchNode = graph.addTaskNode({ name: 'Content Research', prompt: 'Research trending topics in AI and technology...', schedule: 'after:5s' }); const creationNode = graph.addTaskNode({ name: 'Content Creation', prompt: 'Create a blog post summary...', schedule: 'after:10s', dependsOn: ['Content Research'] });

The dependsOn array makes sure tasks run in the right order. If a dependency fails, the tasks that depend on it do not run at all.

Schedule Format Patterns

Astreus uses human-readable schedule strings:

  • daily@06:00 - Execute daily at 6 AM
  • weekly@monday@09:00 - Weekly on Monday at 9 AM
  • monthly@15@10:00 - 15th of each month at 10 AM
  • after:5s - Delay 5 seconds (testing)
  • after:2h - Delay 2 hours
  • every:30m - Repeat every 30 minutes

During development I use short intervals like after:5s so I can test quickly, then switch to the production schedules once the workflow behaves.

Running the Workflow

Execute your workflow with a single call:

TypeScript
const result = await graph.run();

The run method returns detailed execution results:

TypeScript
{ success: true, completedNodes: 2, failedNodes: 0, duration: 15432, results: { 'node-id-1': { output: '...' }, 'node-id-2': { output: '...' } }, errors: [] }

That gives you full visibility into which tasks succeeded, how long they took and what each one produced.

Multi-Step Content Pipeline

Here is a practical example that chains several tasks together:

TypeScript
const agent = await Agent.create({ name: 'ContentAgent', model: 'gpt-4o', systemPrompt: 'You are a content creation specialist.' }); const graph = new Graph({ name: 'Daily Content Pipeline', description: 'Automated content research and creation', maxConcurrency: 2 }, agent); const researchNode = graph.addTaskNode({ name: 'Topic Research', prompt: 'Research trending topics in technology', schedule: 'daily@07:00' }); const draftNode = graph.addTaskNode({ name: 'Draft Creation', prompt: 'Create a blog post draft from research', schedule: 'daily@08:00', dependsOn: ['Topic Research'] }); const optimizeNode = graph.addTaskNode({ name: 'SEO Optimization', prompt: 'Optimize draft for SEO', schedule: 'daily@09:00', dependsOn: ['Draft Creation'] }); const result = await graph.run();

This pipeline researches topics at 7 AM, writes drafts from that research at 8 AM and optimizes them for SEO at 9 AM, every day, without anyone touching it.

Testing with Short Intervals

There is no reason to wait hours between test runs. Use short schedules while you develop:

TypeScript
const testGraph = new Graph({ name: 'Quick Test Pipeline', description: 'Test automated workflow with seconds interval', maxConcurrency: 2 }, agent); const testNode = graph.addTaskNode({ name: 'Quick Test', prompt: 'Test task execution', schedule: 'after:5s' }); const result = await testGraph.run();

With after:5s you can iterate quickly and catch problems early.

Handling Execution Results

Process the workflow results to hook them into other systems:

TypeScript
const result = await graph.run(); if (result.success) { console.log(`Completed ${result.completedNodes} tasks in ${result.duration}ms`); // Access individual task outputs for (const [nodeId, output] of Object.entries(result.results)) { console.log(`${nodeId}:`, output); } } else { console.error(`Failed tasks: ${result.failedNodes}`); result.errors.forEach(error => { console.error(`Error in ${error.nodeId}:`, error.message); }); }

The results object has everything you need to monitor a workflow, debug it and react to how it turned out.

Production Deployment

Deploy your workflow as a long-running process:

TypeScript
import { Agent, Graph } from '@astreus-ai/astreus'; async function main() { const agent = await Agent.create({ name: 'ProductionAgent', model: 'gpt-4o', systemPrompt: 'You are a production workflow agent.' }); const graph = new Graph({ name: 'Production Pipeline', description: 'Automated daily workflows', maxConcurrency: 3 }, agent); // Add your scheduled tasks graph.addTaskNode({ name: 'Daily Report', prompt: 'Generate daily summary report', schedule: 'daily@08:00' }); // Run and keep process alive await graph.run(); process.on('SIGTERM', async () => { console.log('Shutting down gracefully...'); process.exit(0); }); } main().catch(console.error);

This keeps your workflows running and lets the process shut down cleanly when it receives a termination signal.

Best Practices

Most of what makes a workflow reliable has already come up above. Start with after:5s schedules in development so you can test fast. Give nodes descriptive names, because those names are what you will be reading when something breaks. Set a sensible maxConcurrency so you do not overwhelm the APIs you call, and use dependsOn to enforce the order tasks have to run in. Always check result.success before you process any outputs, and keep an eye on result.duration to see where performance can improve. Keep sensitive configuration in environment variables, never in the code.

Complete Example

Explore the full implementation at https://github.com/astreus-ai/astreus. The repository includes working examples, additional patterns, and production-ready configurations.

Next Steps

You can now build automated workflows that run on your schedule. Try a daily report generator, a weekly content summarizer or an hourly data processor. Astreus takes care of the timing and execution, and you get to focus on the tasks themselves.

This experiment is written for Astreus v0.5.37. Please ensure you are using a compatible version.

Keep reading

  • Building Complex Workflows in Astreus

    Build sophisticated multi-agent workflows with advanced orchestration patterns. Learn dependency management, parallel execution, and production-grade pipeline design.

  • Building Basic Graphs in Astreus

    Learn how to create workflow graphs in Astreus with task dependencies and sequential execution. Master the fundamentals of Agent.create(), Graph construction, and addTaskNode() for multi-step AI workflows.

  • Building Agent Persistence in Astreus

    Save and restore agent state. Conversations persist across sessions. Pick up where you left off.