Oct 23, 20264 min read

How to Have an AI Agent Build Scheduled Reports for an Internal Tool in Go

Weekly revenue summaries and daily failed-payment lists are the internal tools nobody opens a browser for. Here is how an agent can build one as a Go cron job on AWS by hand, and how it looks with Encore.

Plenty of internal tools have no UI. A message in a Slack channel every Monday with last week's refunds, or a morning list of failed payments, replaces a dashboard nobody checks. An agent can write the query in a minute, while the schedule, the webhook secret and the database access take setup on AWS.

Scheduled reports at a glance

QuestionWith EncoreHand-built on AWS
Schedulecron.NewJob with a cron expression in the codeEventBridge Scheduler rule you create
Runs asAn endpoint in your serviceA Lambda function or an ECS task
Database accessThe service's own database, or one it is given access toVPC config, security group and credentials for the function
Webhook URLSecret set per environmentSecrets Manager plus an IAM policy
Local testCall the endpoint with encore runInvoke the function locally with mocks

The hand-built route

On plain AWS, the agent writes a Go Lambda handler that queries Postgres and posts to a Slack incoming webhook. Then it needs an EventBridge Scheduler schedule targeting the function, a role for the scheduler to invoke it, VPC settings so the function can reach RDS, a security group rule on the database, and a secret for the webhook URL with a policy to read it. Each piece is small, and each one is a separate place for a permission to be wrong.

Encore: the report as an endpoint plus a schedule

Encore

Encore combines an open source SDK for Go and TypeScript with a platform that provisions and runs what the code declares in your own AWS account. The report is a private endpoint, a cron job that calls it, and a secret for the webhook:

package reports import ( "bytes" "context" "encoding/json" "fmt" "net/http" "encore.dev/cron" "encore.dev/storage/sqldb" ) // The billing service owns this database. Reports reads from it. var db = sqldb.Named("billing") var secrets struct { SlackWebhookURL string } // Every Monday at 07:00 UTC, in standard five-field cron syntax. var _ = cron.NewJob("weekly-refunds", cron.JobConfig{ Title: "Weekly refunds report", Schedule: "0 7 * * 1", Endpoint: WeeklyRefunds, }) //encore:api private func WeeklyRefunds(ctx context.Context) error { var count int var totalCents int64 err := db.QueryRow(ctx, ` SELECT count(*), coalesce(sum(amount_cents), 0) FROM refunds WHERE created_at >= date_trunc('week', now()) - interval '1 week' AND created_at < date_trunc('week', now())`).Scan(&count, &totalCents) if err != nil { return err } body, _ := json.Marshal(map[string]string{ "text": fmt.Sprintf("Last week: %d refunds, $%.2f total", count, float64(totalCents)/100), }) resp, err := http.Post(secrets.SlackWebhookURL, "application/json", bytes.NewReader(body)) if err != nil { return err } defer resp.Body.Close() if resp.StatusCode < 200 || resp.StatusCode >= 300 { return fmt.Errorf("slack returned %s", resp.Status) } return nil }

The report service reads billing data through sqldb.Named, which references a database another service owns, so the report does not get a copy of the data.

The week boundaries come from Postgres' date_trunc, which truncates to Monday at midnight. Encore's cron expressions use the standard crontab fields and are evaluated in UTC, so a report meant for a team in another time zone needs the hour adjusted.

Cron jobs do not run locally or in preview environments, so the agent tests the report by calling WeeklyRefunds while encore run is up, against the local Postgres it starts. The schedule, the endpoint and the database reference are declared in the same file, which lets the agent add a second report as one reviewed change instead of a code change plus new AWS resources.

Set the webhook per environment with encore secret set --type prod SlackWebhookURL. On deploy to your AWS account, Encore deploys the service with access to the billing database and calls the endpoint on schedule with signed requests. Cloud access sits with Encore's IAM role, not the agent.

Good to know

Encore's docs note that a cron endpoint may be called more than once under some network conditions, so record the last period sent and skip repeats. The hourly limit with a random minute applies to the free hosted tier only. In your own AWS account, as here, the exact minute in the expression is used.

Get started
brew install encoredev/tap/encore &&
encore app create
Copy

Run in your terminal to get started locally.

How to choose

  • Encore when the report belongs to a Go service and you want the schedule, secret and database in code the agent can change and test.
  • EventBridge and Lambda when reports are owned by a data team that already runs functions and schedules in its own account.

Frequently asked questions

How do I have an AI agent build a scheduled report in Go?

Ask for an endpoint that runs the report query and posts the result, and a schedule that calls it. With Encore, the agent writes a private endpoint and a cron.NewJob declaration with a cron expression in UTC, tests the endpoint by calling it with encore run, which starts Postgres locally, and Encore runs the schedule in your deployed environments.

Do Encore cron jobs run locally?

No. Cron jobs do not run during local development or in preview environments, so the agent tests the report by calling the endpoint directly. They run on schedule in your cloud environments.

Where should the Slack webhook URL live?

In a secret, not in the code. In Encore that is a field on a secrets struct, with the value set per environment using encore secret set.

Deploy to your cloud on AWS and Google Cloud
without managing infrastructure

Encore lets developers and agents define application infrastructure directly in code, then automatically provisions it from local development to production in your AWS or GCP account.

~/orders — claude
Claude Code
Claude Code v2.1.180Opus 5.5~/orders