← All examples
LocalSQLiteSchedule

Generate a local operations report with no cloud account

Query a local SQLite application database, calculate metrics in JavaScript, generate CSV, and store a versioned report on a schedule.

WOML is useful even when nothing leaves the machine. This workflow uses local application data, local object storage, durable state, and the same inspectable runtime used by networked automation.

The workflow at a glance

Text
Manual or daily trigger
  → Ensure local schema
  → Query recent jobs
  → Calculate operational metrics
  → Generate CSV report
  → Store versioned object
  → Remember latest report reference

The workflow

WOML
<woml>
  <workflow
    id="local-operations-report"
    name="Local operations report"
    description="Build a daily report from a local SQLite database."
    version="1.0.0"
  >
    <config concurrency="1" timeout="5m" queue="local-reports" />

    <triggers>
      <manual id="buildNow" />
      <schedule id="dailyReport" cron="0 18 * * *" timezone="UTC" on-missed="run-once" />
    </triggers>

    <steps>
      <step id="loadJobs" name="Load recent jobs">
        <script>
          const db = services.db({
            driver: "sqlite",
            connection: "./data/operations.sqlite"
          });

          await db.execute({
            text: `
              CREATE TABLE IF NOT EXISTS jobs (
                id TEXT PRIMARY KEY,
                status TEXT NOT NULL,
                duration_ms INTEGER NOT NULL,
                completed_at TEXT NOT NULL
              )
            `
          }, { name: "ensure-local-jobs-table" });

          return db.query({
            text: `
              SELECT id, status, duration_ms, completed_at
              FROM jobs
              WHERE completed_at >= datetime('now', '-1 day')
              ORDER BY completed_at ASC
            `
          });
        </script>
      </step>

      <step id="metrics" name="Calculate metrics">
        <script>
          const jobs = context.steps.loadJobs.rows;
          const succeeded = jobs.filter((job) => job.status === "succeeded").length;
          const failed = jobs.filter((job) => job.status === "failed").length;
          const averageDurationMs = jobs.length === 0
            ? 0
            : Math.round(jobs.reduce((sum, job) => sum + job.duration_ms, 0) / jobs.length);

          return {
            generatedAt: new Date().toISOString(),
            total: jobs.length,
            succeeded,
            failed,
            successRate: jobs.length === 0 ? 1 : succeeded / jobs.length,
            averageDurationMs,
            jobs
          };
        </script>
      </step>

      <step id="storeReport" name="Generate and store CSV report">
        <script>
          const header = "id,status,duration_ms,completed_at";
          const rows = context.steps.metrics.jobs.map((job) =>
            [job.id, job.status, job.duration_ms, job.completed_at]
              .map((value) => JSON.stringify(String(value)))
              .join(",")
          );
          const csv = [header, ...rows].join("\n");
          const date = context.steps.metrics.generatedAt.slice(0, 10);

          const object = await services.storage.put({
            key: `operations-reports/${date}.csv`,
            text: csv,
            contentType: "text/csv",
            overwrite: true
          });

          return {
            report: object,
            total: context.steps.metrics.total,
            failed: context.steps.metrics.failed,
            successRate: context.steps.metrics.successRate
          };
        </script>
      </step>

      <step id="rememberLatest" name="Remember latest report">
        <script>
          await services.state.set(
            "latest-operations-report",
            context.steps.storeReport.report,
            { name: "remember-latest-operations-report" }
          );

          return context.steps.storeReport;
        </script>
      </step>
    </steps>
  </workflow>
</woml>

Run it locally

Create the application-data directory, then run the workflow:

Terminal
mkdir -p data
woml check local-operations-report.woml
woml run local-operations-report.woml

Press Enter to generate a report immediately. The schedule keeps the runtime active for the next daily report. Add rows to data/operations.sqlite from your application or SQLite client.

Why this shows WOML's range

There is no SaaS connector and no external account. WOML acts as a local automation runtime with SQL, arbitrary JavaScript calculations, versioned object storage, durable cross-run memory, schedules, manual execution, logs, inspection, backups, and retention.