Agent Reference
Embercore is built around five specialised agents, each named after a Greek deity. They work together in a pipeline: Athena creates the plan, Hermes orchestrates execution, Apollo writes copy, Hephaestus assembles deliverables, and Hestia manages persistence.
Brief → Athena (plan) → Hermes (execute) → Apollo / Hephaestus → Artifacts
↕
Hestia (persist)
All agents live under packages/engine/agents/.
Athena — The Planner
Package: agents/athena
Athena takes a product brief or campaign goal and generates a structured YAML plan that orchestrates the other agents. Each plan contains checkpoints with dependency ordering, agent assignments, and expected outputs.
API
// New creates an Athena planner. Pass nil for h to disable persistence.
func New(p provider.Provider, h *hestia.Hestia) *Athena
// GeneratePlan takes a product brief and generates a structured plan.
// Calls the LLM with a planning prompt, parses YAML, validates, and
// optionally persists via Hestia.
func (a *Athena) GeneratePlan(ctx context.Context, brief string, opts PlanOpts) (*PlanSpec, error)
// ParsePlan unmarshals raw YAML bytes into a PlanSpec and validates it.
func ParsePlan(yamlBytes []byte) (*PlanSpec, error)
// ValidatePlan checks structural invariants: at least one checkpoint,
// no duplicate IDs, valid dependency references, no circular dependencies,
// and all agents are in the known set.
func ValidatePlan(plan *PlanSpec) error
// ExtractYAML pulls the YAML block out of an LLM response.
func ExtractYAML(raw string) ([]byte, error)
// ToYAML marshals a PlanSpec back to YAML bytes.
func ToYAML(plan *PlanSpec) ([]byte, error)
Options
type PlanOpts struct {
Name string // plan name (default: "untitled-plan")
Workflow string // "launch-announcement", "weekly-newsletter", or "custom"
Agents []string // which agents to include (default: all five)
MaxSteps int // max checkpoints (default: 10)
Persist bool // save to Hestia (default: true if hestia != nil)
}
Types
PlanSpec
The top-level plan schema matching the YAML format used across all Embercore plans.
| Field |
Type |
Description |
Name |
string |
Human-readable plan name |
Version |
string |
Schema version |
Description |
string |
What this plan does |
AgentsUsed |
[]string |
Agents referenced in checkpoints |
Inputs |
[]InputSpec |
Runtime parameters the plan requires |
Checkpoints |
[]StepSpec |
Ordered execution steps |
| Field |
Type |
Description |
Name |
string |
Parameter name |
Type |
string |
Data type (e.g. "string", "file") |
Required |
bool |
Whether the input is mandatory |
Description |
string |
What this input is for |
StepSpec
| Field |
Type |
Description |
ID |
string |
Unique step identifier |
Agent |
string |
Agent name (must be in KnownAgents) |
Action |
string |
What the agent should do |
DependsOn |
[]string |
IDs of steps that must complete first |
Outputs |
[]string |
Expected output artifacts |
KnownAgents
var KnownAgents = map[string]bool{
"Athena": true, "Apollo": true, "Hephaestus": true,
"Hestia": true, "Hermes": true,
}
Example
package main
import (
"context"
"fmt"
"log"
"github.com/embercore-labs/embercore/packages/engine/agents/athena"
"github.com/embercore-labs/embercore/packages/engine/internal/provider"
)
func main() {
p, err := provider.NewFromEnv()
if err != nil {
log.Fatal(err)
}
a := athena.New(p, nil) // nil hestia = no persistence
spec, err := a.GeneratePlan(context.Background(), "Launch a developer newsletter", athena.PlanOpts{
Name: "dev-newsletter-launch",
MaxSteps: 8,
})
if err != nil {
log.Fatal(err)
}
yamlBytes, _ := athena.ToYAML(spec)
fmt.Println(string(yamlBytes))
}
CLI
# Generate a plan
embercore plan "Launch a SaaS product for project management"
# Save to file
embercore plan "Weekly newsletter campaign" -o newsletter.yaml
# Use a specific provider
embercore plan "Product launch" --provider openai --model gpt-4o
Hermes — The Executor
Package: agents/hermes
Hermes is the execution orchestrator. It takes a parsed plan and runs each step in topological order, pausing at checkpoints for human approval when a handler is configured. Hermes manages run lifecycle via Hestia and supports resume-from-checkpoint for interrupted runs.
API
// New creates a Hermes engine instance.
func New(p provider.Provider, h *hestia.Hestia, logger *slog.Logger) *Hermes
// ExecutePlan runs a plan from the beginning. Creates a Run via Hestia,
// then walks topologically-sorted layers, executing steps and pausing
// at checkpoints when required.
func (h *Hermes) ExecutePlan(ctx context.Context, spec *plan.Spec, opts ExecOpts) (*ExecResult, error)
// ResumePlan resumes a paused run from the last completed checkpoint.
func (h *Hermes) ResumePlan(ctx context.Context, runID string) (*ExecResult, error)
// WithCheckpointHandler sets a custom handler for checkpoint pauses.
// If not set, ExecutePlan pauses the run and returns status "paused".
func (h *Hermes) WithCheckpointHandler(handler CheckpointHandler) *Hermes
Types
ExecOpts
| Field |
Type |
Description |
AutoApprove |
bool |
Skip checkpoint approval prompts |
PlanID |
string |
Existing plan ID (if already persisted) |
InputData |
map[string]interface{} |
Runtime inputs for plan parameters |
ExecResult
| Field |
Type |
Description |
RunID |
string |
UUID of this execution run |
Status |
string |
"completed", "paused", or "failed" |
Steps |
[]StepResult |
Per-step results |
Error |
error |
Error details if failed |
StepResult
| Field |
Type |
Description |
StepID |
string |
ID of the executed step |
Agent |
string |
Agent that ran the step |
Status |
string |
"completed", "failed", or "skipped" |
Output |
string |
Agent output content |
Elapsed |
time.Duration |
Wall-clock execution time |
CheckpointHandler
// Called at each checkpoint pause.
// Return true to approve and continue, false to reject/pause.
type CheckpointHandler func(step plan.Step, output string) (approved bool, feedback string, err error)
Example
package main
import (
"context"
"fmt"
"log"
"log/slog"
"os"
"github.com/embercore-labs/embercore/packages/engine/agents/hermes"
"github.com/embercore-labs/embercore/packages/engine/agents/hestia"
"github.com/embercore-labs/embercore/packages/engine/internal/provider"
"github.com/embercore-labs/embercore/packages/engine/plan"
)
func main() {
p, _ := provider.NewFromEnv()
h, _ := hestia.New("data.db")
spec, _ := plan.Parse([]byte(`
name: demo
version: "1"
description: Demo plan
agents_used: [Athena]
checkpoints:
- id: step1
agent: Athena
action: "Generate outline"
outputs: [outline.md]
`))
herm := hermes.New(p, h, slog.Default())
// Auto-approve all checkpoints
result, err := herm.ExecutePlan(context.Background(), spec, hermes.ExecOpts{
AutoApprove: true,
})
if err != nil {
log.Fatal(err)
}
fmt.Printf("Run %s: %s (%d steps)\n", result.RunID, result.Status, len(result.Steps))
}
CLI
# Run by plan ID
embercore run <plan-id>
# Run from a YAML file
embercore run my-plan.yaml
# Auto-approve all checkpoints
embercore run <plan-id> --auto-approve
# Resume a paused run
embercore resume <run-id>
Apollo — The Copywriter
Package: agents/apollo
Apollo generates marketing copy across seven content types: blog posts, emails, social media posts, headlines, ads, landing pages, and newsletters. It supports tone control, audience targeting, word count constraints, SEO keyword integration, and iterative refinement.
API
// New creates an Apollo agent with the given options.
func New(opts ...Option) *Apollo
// GenerateCopy produces marketing content based on the request.
// Builds a specialised prompt, calls the LLM, and parses the response
// into a structured CopyResult with metadata and optional variants.
func (a *Apollo) GenerateCopy(ctx context.Context, req CopyRequest) (*CopyResult, error)
// Refine takes existing copy and feedback, then generates an improved version.
// The original result is preserved; a new CopyResult is returned.
func (a *Apollo) Refine(ctx context.Context, original *CopyResult, feedback string) (*CopyResult, error)
Options
// WithProvider sets the LLM provider.
func WithProvider(p provider.Provider) Option
// WithHestia enables persistence via Hestia.
func WithHestia(h *hestia.Hestia) Option
// WithModel overrides the default model for completions.
func WithModel(m string) Option
Types
ContentType
| Constant |
Value |
Description |
TypeBlog |
"blog" |
Blog post |
TypeEmail |
"email" |
Email body |
TypeSocial |
"social" |
Social media post |
TypeHeadline |
"headline" |
Headline / tagline |
TypeAd |
"ad" |
Advertisement copy |
TypeLanding |
"landing-page" |
Landing page content |
TypeNewsletter |
"newsletter" |
Newsletter edition |
CopyRequest
| Field |
Type |
Description |
Type |
ContentType |
Kind of content to generate |
Brief |
string |
What to write about |
Tone |
string |
"professional", "casual", "playful", "urgent", "inspirational" |
Audience |
string |
Target audience description |
Constraints |
Constraints |
Word count, format, platform, SEO |
Context |
[]string |
Additional context or reference material |
Constraints
| Field |
Type |
Description |
MaxWords |
int |
Maximum word count |
MinWords |
int |
Minimum word count |
Platform |
string |
"twitter", "linkedin", "instagram", "facebook" |
Format |
string |
"markdown", "html", "plain" |
Keywords |
[]string |
SEO keywords to include |
CTAText |
string |
Call-to-action text |
CopyResult
| Field |
Type |
Description |
Content |
string |
Generated copy |
Type |
ContentType |
Content type used |
WordCount |
int |
Word count of output |
Metadata |
CopyMetadata |
Quality signals |
Variants |
[]Variant |
Alternative versions (social/ad types) |
| Field |
Type |
Description |
Tone |
string |
Detected tone |
ReadingLevel |
string |
"easy", "moderate", "advanced" |
SEOScore |
int |
0–100 based on keyword inclusion |
Suggestions |
[]string |
Improvement suggestions |
Variant
| Field |
Type |
Description |
Label |
string |
e.g. "shorter", "more casual", "with emoji" |
Content |
string |
Alternative content |
Example
package main
import (
"context"
"fmt"
"log"
"github.com/embercore-labs/embercore/packages/engine/agents/apollo"
"github.com/embercore-labs/embercore/packages/engine/internal/provider"
)
func main() {
p, _ := provider.NewFromEnv()
a := apollo.New(
apollo.WithProvider(p),
apollo.WithModel("claude-sonnet-4-20250514"),
)
result, err := a.GenerateCopy(context.Background(), apollo.CopyRequest{
Type: apollo.TypeBlog,
Brief: "Write a blog post about the benefits of local-first AI tools for solo founders",
Tone: "professional",
Audience: "indie hackers and solo SaaS founders",
Constraints: apollo.Constraints{
MinWords: 800,
MaxWords: 1500,
Keywords: []string{"local-first", "AI tools", "solo founder"},
CTAText: "Try Embercore today",
},
})
if err != nil {
log.Fatal(err)
}
fmt.Printf("Word count: %d | SEO Score: %d\n", result.WordCount, result.Metadata.SEOScore)
fmt.Println(result.Content)
// Refine based on feedback
revised, _ := a.Refine(context.Background(), result, "Make it more conversational and add a personal anecdote intro")
fmt.Println(revised.Content)
}
Hephaestus — The Builder
Package: agents/hephaestus
Hephaestus assembles content from other agents into final deliverables: HTML emails, formatted blog posts, social media packages, campaign kits, landing pages, and newsletters. It supports three assembly strategies: named templates, LLM-enhanced assembly, and deterministic (no-LLM) assembly.
API
// New creates a Hephaestus agent with the given options.
func New(opts ...Option) *Hephaestus
// Build assembles a deliverable from content pieces. It tries in order:
// 1. Named template (if Template is set)
// 2. LLM-enhanced assembly (if provider is available)
// 3. Deterministic assembly using built-in assembler functions
func (h *Hephaestus) Build(ctx context.Context, req BuildRequest) (*BuildResult, error)
// BuildFromTemplate is a convenience method that assembles content
// using a named built-in template.
func (h *Hephaestus) BuildFromTemplate(ctx context.Context, templateName string, data map[string]string) (*BuildResult, error)
Options
// WithProvider sets the LLM provider for enhanced assembly.
func WithProvider(p provider.Provider) Option
// WithHestia enables persistence via Hestia.
func WithHestia(h *hestia.Hestia) Option
// WithModel overrides the default model for completions.
func WithModel(m string) Option
// WithRunID sets the run ID for artifact persistence.
func WithRunID(id string) Option
Types
OutputType
| Constant |
Value |
Description |
TypeEmailHTML |
"email-html" |
HTML email |
TypeBlogPost |
"blog-post" |
Formatted blog post |
TypeSocialPack |
"social-pack" |
Multi-platform social package |
TypeCampaignKit |
"campaign-kit" |
Bundle of multiple deliverables |
TypeLandingPage |
"landing-page" |
Landing page HTML |
TypeNewsletterHTML |
"newsletter-html" |
Newsletter HTML |
| Constant |
Value |
FormatHTML |
"html" |
FormatMarkdown |
"markdown" |
FormatPlaintext |
"plaintext" |
FormatJSON |
"json" |
BuildRequest
| Field |
Type |
Description |
Type |
OutputType |
Kind of deliverable to build |
Content |
map[string]string |
Keyed content pieces (e.g. "headline", "body") |
Template |
string |
Optional named template |
Format |
OutputFormat |
Output format override |
Assets |
[]Asset |
Images, attachments, logos |
Config |
BuildConfig |
Assembly configuration |
BuildConfig
| Field |
Type |
Description |
Brand |
BrandKit |
Brand identity values |
Responsive |
bool |
Generate responsive HTML |
Inline |
bool |
Inline CSS (for email clients) |
MinifyHTML |
bool |
Minify output HTML |
BrandKit
| Field |
Type |
Description |
PrimaryColor |
string |
Primary brand colour |
SecondaryColor |
string |
Secondary brand colour |
FontFamily |
string |
CSS font family |
LogoURL |
string |
URL to logo image |
CompanyName |
string |
Company name for footer |
FooterText |
string |
Custom footer text |
BuildResult
| Field |
Type |
Description |
Output |
string |
Assembled content |
Format |
OutputFormat |
Output format |
Type |
OutputType |
Deliverable type |
Artifacts |
[]ArtifactRef |
Persisted artifact references |
Warnings |
[]string |
Any issues during assembly |
Built-in templates
| Template Name |
Output Type |
Format |
"email-basic" |
email-html |
HTML |
"blog-standard" |
blog-post |
Markdown |
"social-thread" |
social-pack |
Plaintext |
Example
package main
import (
"context"
"fmt"
"log"
"github.com/embercore-labs/embercore/packages/engine/agents/hephaestus"
"github.com/embercore-labs/embercore/packages/engine/internal/provider"
)
func main() {
p, _ := provider.NewFromEnv()
h := hephaestus.New(
hephaestus.WithProvider(p),
)
// Build an HTML email from content pieces
result, err := h.Build(context.Background(), hephaestus.BuildRequest{
Type: hephaestus.TypeEmailHTML,
Content: map[string]string{
"headline": "Introducing Embercore",
"body": "Build your marketing engine with AI agents...",
"cta_text": "Get Started Free",
"cta_url": "https://embercore.dev",
"email_subject": "Your marketing just got an upgrade",
},
Config: hephaestus.BuildConfig{
Brand: hephaestus.BrandKit{
PrimaryColor: "#FF6B35",
CompanyName: "Embercore Labs",
FontFamily: "Inter, sans-serif",
},
Inline: true,
MinifyHTML: true,
},
})
if err != nil {
log.Fatal(err)
}
fmt.Printf("Format: %s | Size: %d bytes\n", result.Format, len(result.Output))
// Or use a template
tmplResult, _ := h.BuildFromTemplate(context.Background(), "email-basic", map[string]string{
"headline": "Weekly Update",
"body": "Here's what happened this week...",
})
fmt.Println(tmplResult.Output)
}
Hestia — The Memory Agent
Package: agents/hestia
Hestia is the persistence layer — a thin wrapper over the SQLite store that composes storage operations into workflow patterns. All other agents use Hestia to save plans, track runs, record checkpoints, persist artifacts, and support resume-from-checkpoint.
API
// New creates a Hestia instance backed by SQLite at dbPath.
func New(dbPath string) (*Hestia, error)
// SavePlan creates a plan with initial metadata. Returns the plan ID.
func (h *Hestia) SavePlan(ctx context.Context, name, yamlContent, brief string) (string, error)
// StartRun creates a new run for the given plan and sets the plan to active.
// Returns the run ID.
func (h *Hestia) StartRun(ctx context.Context, planID string) (string, error)
// RecordCheckpoint creates a completed checkpoint for a run.
func (h *Hestia) RecordCheckpoint(ctx context.Context, runID, stepID, agent, output string) error
// GetRunState returns the full state tree: run, plan, checkpoints, artifacts.
func (h *Hestia) GetRunState(ctx context.Context, runID string) (*store.RunState, error)
// ResumeRun finds the last completed checkpoint and returns the state
// needed to resume execution from that point.
func (h *Hestia) ResumeRun(ctx context.Context, runID string) (*store.RunState, error)
Hestia also embeds *store.Store, exposing these lower-level methods:
// Plans
func (s *Store) CreatePlan(ctx context.Context, p Plan) (string, error)
func (s *Store) GetPlan(ctx context.Context, id string) (*Plan, error)
func (s *Store) ListPlans(ctx context.Context, opts ListOpts) ([]Plan, error)
func (s *Store) UpdatePlanStatus(ctx context.Context, id, status string) error
// Runs
func (s *Store) CreateRun(ctx context.Context, r Run) (string, error)
func (s *Store) GetRun(ctx context.Context, id string) (*Run, error)
func (s *Store) GetLatestRun(ctx context.Context, planID string) (*Run, error)
func (s *Store) UpdateRunStatus(ctx context.Context, id, status, currentStep string) error
func (s *Store) ListRuns(ctx context.Context, planID string, opts ListOpts) ([]Run, error)
// Checkpoints
func (s *Store) CreateCheckpoint(ctx context.Context, cp Checkpoint) (string, error)
func (s *Store) GetCheckpoint(ctx context.Context, id string) (*Checkpoint, error)
func (s *Store) ListCheckpointsByPlan(ctx context.Context, planID string) ([]Checkpoint, error)
func (s *Store) UpdateCheckpointStatus(ctx context.Context, id, status string) error
func (s *Store) ApproveCheckpoint(ctx context.Context, id, approvedBy string) error
// Artifacts
func (s *Store) CreateArtifact(ctx context.Context, a Artifact) (string, error)
func (s *Store) GetArtifact(ctx context.Context, id string) (*Artifact, error)
func (s *Store) ListArtifactsByRun(ctx context.Context, runID string) ([]Artifact, error)
Types
See Architecture Guide — Storage Models for the full Plan, Run, Checkpoint, Artifact, and RunState type definitions.
Example
package main
import (
"context"
"fmt"
"log"
"github.com/embercore-labs/embercore/packages/engine/agents/hestia"
"github.com/embercore-labs/embercore/packages/engine/internal/store"
)
func main() {
h, err := hestia.New("~/.embercore/data.db")
if err != nil {
log.Fatal(err)
}
ctx := context.Background()
// Save a plan
planID, _ := h.SavePlan(ctx, "My Campaign", "<yaml>...</yaml>", "Launch a newsletter")
fmt.Println("Plan:", planID)
// Start a run
runID, _ := h.StartRun(ctx, planID)
fmt.Println("Run:", runID)
// Record a checkpoint
_ = h.RecordCheckpoint(ctx, runID, "step-1", "Athena", "Generated outline")
// Get full state
state, _ := h.GetRunState(ctx, runID)
fmt.Printf("Run status: %s, Checkpoints: %d\n", state.Run.Status, len(state.Checkpoints))
// List all plans
plans, _ := h.ListPlans(ctx, store.ListOpts{Limit: 10})
for _, p := range plans {
fmt.Printf(" %s: %s (%s)\n", p.ID, p.Name, p.Status)
}
}
CLI
# List all plans (uses Hestia internally)
embercore status
# Show plan detail with checkpoints
embercore status <plan-id>
Agent Interaction Map
┌──────────────────────────────────────────────────────────┐
│ User / MCP Client │
└──────────────────────────┬───────────────────────────────┘
│ Brief
▼
┌───────────────┐
│ Athena │ plan generation
│ (planner) │
└───────┬───────┘
│ PlanSpec (YAML)
▼
┌───────────────┐
│ Hermes │ topological execution
│ (executor) │◄──── CheckpointHandler
└───────┬───────┘
│ dispatches steps to:
┌────────┼────────┐
▼ │ ▼
┌──────────┐ │ ┌────────────┐
│ Apollo │ │ │ Hephaestus │
│ (copy) │ │ │ (build) │
└────┬─────┘ │ └─────┬──────┘
│ │ │
└─────┬─────┘ │
│ │
▼ ▼
┌──────────────────────┐
│ Hestia │ persistence
│ (SQLite store) │
└──────────────────────┘
See Also