deploy

package
v0.0.6 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Apr 22, 2026 License: MIT Imports: 18 Imported by: 0

README

Deploy Intelligence Pipeline

This package powers the clanker deploy intelligence flow from user query to plan/apply.

Rule-Pack Layer

The deploy package now has a small typed rule-pack layer in internal/deploy/rule_packs.go.

  • Provider packs hold provider-specific hooks such as DigitalOcean autofix/validation and AWS validation.
  • App packs hold app-specific hooks such as OpenClaw and WordPress architecture defaults, prompt requirements, and app-aware autofix/validation.
  • The current implementation is intentionally thin: it routes to the existing low-level logic instead of replacing it.
  • Goal: reduce drift between prompt text, autofix, deterministic validation, and future backend parity work while keeping generic one-click deploy behavior intact.

Related shared text/helpers:

Current Typed Seams

Most of the package is still intentionally pragmatic and string-heavy, but a few narrow typed seams now exist to keep the highest-risk OpenClaw DigitalOcean paths deterministic without rewriting the whole planner.

  • Rule-pack routing in internal/deploy/rule_packs.go is the small typed dispatch layer for provider/app hooks.
  • Skeleton capability hints in internal/deploy/skeleton_plan.go attach lightweight provider/app/runtime constraints to the high-level plan before hydration. Those hints are now also stamped onto hydrated plan JSON as plan-level capabilities metadata for downstream backend normalization/preflight. The paged fallback planner now stamps the same inferred plan-level capabilities so backend checks do not lose metadata when skeleton generation is skipped. WordPress on AWS now emits richer capability metadata too, so backend review/repair and preflight can keep the EC2 + ALB + Docker Hub runtime shape intact. OpenClaw on AWS now emits stronger EC2 + ALB + CloudFront capability metadata as well, so backend checks can keep the required HTTPS pairing shape. Backend normalization also uses that metadata now, so OpenClaw AWS autofill for CloudFront outputs/waiters and ECR pull viability still works even when the raw plan text is sparse. Backend AWS normalization also uses WordPress capability metadata to strip accidental ECR/build flows and normalize the ALB health-check path back to /wp-login.php. Backend app detection for rule-pack routing and advisory normalization is now centralized too, reducing drift between OpenClaw and WordPress matching paths. Backend capability step-family matching is centralized now as well, so required/forbidden capability checks and app-specific preflight use the same command-family view.
  • OpenClaw DO bootstrap canonicalization in internal/deploy/openclaw_rules.go infers a minimal bootstrap spec from droplet user-data and renders one canonical script shape.
  • OpenClaw DO firewall canonicalization in internal/deploy/openclaw_rules.go lifts firewall rule strings into a small typed firewall spec, then re-renders one canonical doctl compute firewall rule layout.
  • DigitalOcean command-schema gating in internal/deploy/do_command_schema.go rejects hallucinated command families early, enforces placeholder production order across paged planning, and blocks strict-schema regressions during repair/review.
  • Semantic graph compilation in internal/deploy/semantic_graph.go and internal/deploy/semantic_graph_digitalocean.go infers a typed provider/app/runtime graph from the LLM plan and recompiles that graph into canonical provider commands before final validation/execution.

Current OpenClaw DigitalOcean invariants:

  • OpenClaw runtime image is built on the droplet with docker build -t openclaw:local .
  • App Platform provides the managed HTTPS front door on a DigitalOcean-owned hostname
  • DOCR is allowed only for the small App Platform proxy image, not for the OpenClaw runtime image
  • inbound TCP must include 22, 18789, and 18790
  • outbound must include tcp/all, udp/all, and icmp/all
  • empty address: fields are normalized to 0.0.0.0/0
  • repeated --inbound-rules / --outbound-rules flags are merged into one canonical arg each
  • droplet-facing firewall rules stay on the gateway ports only; browser HTTPS comes from App Platform rather than droplet ports 80 or 443
  • plans must include compute ssh-key import, compute firewall create, compute droplet create, compute firewall add-droplets, registry create, registry login, docker build, docker push, and apps create
  • after apps create resolves the managed HTTPS URL, the executor patches gateway.controlUi.allowedOrigins over SSH on the droplet

This is the current architecture direction: keep planning broad and non-deterministic, then lower the riskiest execution surfaces into small typed canonical forms.

For the DigitalOcean OpenClaw path, the executable artifact is no longer treated as raw LLM command text alone. The pipeline now:

  • keeps the LLM responsible for repo analysis, intent, and high-level plan shape
  • infers a semantic graph from the generated DO plan
  • recompiles that graph into canonical DO commands for firewall, bootstrap, registry, droplet, and App Platform proxy steps
  • runs deterministic and LLM validation on the compiled output

Query → Deploy (Current Flow)

  1. Input + context setup

    • cmd/deploy.go parses flags, provider/profile, and AI settings.
    • Repo is cloned and profiled (CloneAndAnalyze) for language, framework, ports, Docker/Compose, env hints.
  2. Intelligence pipeline (RunIntelligence)

    • Phase 0: Explore repo (explorer.go) — agentic file reads to gather missing context.
    • Phase 1: Deep analysis (intelligence.go) — app behavior, services, startup/build commands, env requirements.
    • Phase 1.25: Docker analysis (docker_agent.go) — Docker/Compose topology, primary port, container runtime hints.
    • Phase 1.5: Infra scan (infra_scan.go, cf_infra_scan.go) — existing cloud resources to reuse.
    • Phase 2: Architecture decision (intelligence.go) — method/provider recommendation (e.g. EC2 for OpenClaw).
    • App rule packs can apply deterministic architecture overrides and append app/provider deployment requirements to the planning prompt.
    • Produces EnrichedPrompt for planning.
  3. Skeleton + hydrate plan generation (skeleton_plan.go) — primary path

    • Phase 3a: Skeleton — single LLM call produces a lightweight PlanSkeleton (service, operation, reason, produces, dependsOn per step). No real CLI args yet.
    • Skeletons now also carry lightweight typed Capabilities hints so provider/app/runtime constraints survive into hydration without forcing a rigid full-plan schema.
    • Skeleton is validated (validateSkeleton): checks required launch ops are present, flags duplicates using a composite key of (service, operation, produces, dependsOn).
    • Capability-aware validation also checks required/forbidden step families for typed cases such as OpenClaw on DigitalOcean.
    • Phase 3b: Hydrate — skeleton steps are batched (max 5 consecutive independent steps per batch) and each batch is hydrated into real maker.Command structs via separate LLM calls.
    • Hydrate prompts receive the same capability hints so later detail generation keeps the same execution model.
    • Hydrated commands are now checked structurally against the requested skeleton step family and capability constraints before they are accepted.
    • Hydrate prompts enforce resource name consistency across steps (e.g. ECR repo names in user-data must match earlier ecr create-repository commands).
    • If skeleton or hydration fails, falls back to the paged plan generation path.

    3b. Paged plan generation (paged_plan.go) — fallback path

    • Plan is generated in small command pages instead of one large response.
    • Each page is parsed (ParsePlanPage), normalized via maker.ParsePlan, and appended with dedupe (AppendPlanPage).
    • Parser tolerates either a page object or a plain command array ([]commands) from the LLM.
    • Page prompts include current command tail + produced bindings + required launch operations + unresolved hard issues.
    • When both skeleton and paged plans exist, the one with fewer deterministic issues wins.
  4. Generic plan autofix (plan_autofix.go)

    • Runs after plan generation (both skeleton and paged paths).
    • Before generic cleanup, matching rule packs may run app/provider-specific autofix hooks (for example OpenClaw and DigitalOcean passes).
    • DigitalOcean autofix in internal/deploy/do_plan_autofix.go is currently the main deterministic cleanup point for droplet user-data and firewall command repair.
    • Structured plan transforms in cmd/deploy.go now also pass supported plans through the semantic graph compiler after rule-pack autofix and before final generic cleanup.
    • SSM semantic dedup — deduplicates SSM send-command / put-parameter steps that do the same thing.
    • Launch cycle dedup — removes redundant run-instances cycles within the same project.
    • Read-only dedup — collapses repeated read-only commands (describe/get/list).
    • Orphan placeholder pruning — removes commands that reference <PLACEHOLDER> values never produced by any earlier command. Accepts externalBindings (user-provided env var names) so user env vars are treated as "produced" and not orphan-pruned.
    • User-data placeholder normalization — rewrites <USER_DATA_*> variants to canonical <USER_DATA>.
    • Critical command protectionrun-instances, create-load-balancer, create-distribution are never removed by autofix.
  5. Deterministic guardrails (plan_preflight_validate.go)

    • Deterministic checks run for hard failures:
      • launch step missing,
      • OpenClaw onboarding/compose requirements,
      • missing compose-required env vars,
      • secret inlining,
      • AWS wiring sanity checks.
    • DigitalOcean strict-schema checks now also reject fake command families, enforce placeholder production order during paging/repair, and verify the OpenClaw droplet plus App Platform proxy image flow stays internally consistent.
    • DigitalOcean validation now also reads firewall rules through the typed OpenClaw DO firewall spec so repeated flags, missing required ports, and bad plain-droplet ingress are checked from one normalized view.
    • Provider/app rule packs contribute deterministic validation hooks so provider-specific and app-specific checks are routed from one place.
    • Waiter/order sanity for AWS runtime wiring (ec2 wait instance-running before target registration, elbv2 wait load-balancer-available before listener creation).
    • CloudFront command-shape sanity (create-distribution must not carry --tags) and OpenClaw output contract (CLOUDFRONT_DOMAIN + full HTTPS_URL with https://).
    • User-data vs plan cross-check (crossCheckUserDataVsPlan) — decodes base64 user-data from run-instances commands, extracts ECR image references, and verifies they match ECR repositories created in the plan. Catches hallucinated repo name mismatches.
    • Bulk invariant checks:
      • non-empty command list, no unresolved placeholders,
      • IAM instance-profile readiness before EC2 launch,
      • user-data quote sanity (detects unterminated quote breakages).
    • Project overlay invariants:
      • OpenClaw: provider-appropriate HTTPS pairing URL, onboarding before gateway start.
    • Stuck detection fails fast in --apply; in plan-only mode it logs warnings and returns best-effort output.
  6. Deterministic repair + triage

    • If planning ends with deterministic issues, repair rounds (plan_repair_agent.go) patch the plan JSON and re-validate.
    • Findings are triaged (plan_issue_triage.go) into hard-fixable, likely-noise, and context-needed.
    • Repair prompts enforce strict contract: preserve valid commands, minimal diff, fix only listed issues.
    • User-data micro-repair — targeted LLM fix for user-data script issues without touching the rest of the plan.
  7. Conservative sanitizer (plan_sanitize.go)

    • Sanitization is fail-open: original vs sanitized plans are compared via deterministic issue count.
    • Sanitized plan is used only when it is not worse than original.
    • Includes generic arg normalization and safe command cleanup across providers.
  8. LLM validation + repair (ValidatePlan)

    • Once deterministic checks pass, the LLM validator reviews ordering/missing steps/port/env/IAM chaining.
    • If invalid, repair rounds rewrite plan JSON and re-validate.
    • Repair/review parsing uses LLM JSON-repair helpers (llm_plan_integrity.go) before giving up on a candidate.
    • Retention guard is issue-driven: allows focused removals when issues/fixes justify them, blocks broad command collapse.
  9. Final review + integrity passes

    • Review agent (plan_review_agent.go) — non-blocking pass that can append missing commands.
    • Generic integrity pass (llm_plan_integrity.go) — provider-agnostic minimal-diff fixes (tokenization, waiter usage, run-instances flag/script boundary, CloudFront config shape) without architecture drift.
  10. Plan finalize + apply orchestration

    • Placeholder/binding resolution and provider-specific enrichment.
    • In --apply, execution is staged (infra → build/push → workload launch → verification).
    • OpenClaw apply path seeds runtime env bindings from collected config and process env.
    • --enforce-image-deploy forces ECR image-based deploy (build/push + pull/run).
    • SSH safety rule: plans with SSH ingress on port 22 need explicit CIDR or fall back to SSM-only.
    • Auto-remediation prompts include deployment intent so self-heal stays aligned.

Compact Sequence Diagram

sequenceDiagram
    autonumber
    participant U as User
    participant C as cmd/deploy.go
    participant I as RunIntelligence
    participant S as Skeleton+Hydrate
    participant P as Paged Planner (fallback)
    participant A as Generic Autofix
    participant D as Deterministic Validator
    participant R as Plan Repair Agent
    participant V as LLM Validator
    participant E as Maker Executor

    U->>C: clanker deploy <repo>
    C->>C: Clone + static profile
    C->>I: RunIntelligence(profile, provider)
    I-->>C: enriched prompt + architecture + infra hints

    C->>S: GeneratePlanSkeleton (1 LLM call)
    S-->>C: PlanSkeleton (steps + placeholders)
    C->>S: HydrateSkeleton (batched LLM calls)
    S-->>C: hydrated plan commands

    alt skeleton/hydrate failed
      loop page 1..N
        C->>P: BuildPlanPagePrompt(current state)
        P-->>C: {done, commands[]}
      end
    end

    C->>A: ApplyGenericPlanAutofix(plan, externalBindings)
    A-->>C: deduped + pruned plan

    C->>D: deterministic validate (+ crossCheckUserDataVsPlan)
    D-->>C: hard issues / pass

    alt deterministic issues
      C->>R: user-data micro-repair / full repair
      R-->>C: patched plan
      C->>D: re-validate
    end

    C->>C: SanitizePlanConservative

    C->>V: LLM validate + repair loop
    V-->>C: validated plan

    alt --apply
      C->>E: execute staged plan
      E-->>U: deploy result + outputs
    else plan-only
      C-->>U: plan JSON + warnings
    end

Key Files

  • rule_packs.go — typed provider/app rule-pack registry and hook routing
  • do_command_helpers.go — shared DigitalOcean command-shape helpers (droplet detection, flag counting, user-data extraction)
  • openclaw_rules.go — shared OpenClaw DigitalOcean rule text plus typed bootstrap/firewall canonicalization helpers
  • semantic_graph.go — provider/app/runtime semantic graph model and build/compile dispatch
  • semantic_graph_digitalocean.go — DigitalOcean OpenClaw semantic graph inference and canonical command compiler
  • skeleton_plan.go — two-phase skeleton+hydrate plan generation (primary path)
  • paged_plan.go — paginated planning protocol (fallback path)
  • plan_autofix.go — generic plan autofix (dedup, orphan pruning, critical command protection)
  • do_plan_autofix.go — DigitalOcean-specific deterministic cleanup for doctl arg repair, user-data repair, and OpenClaw firewall normalization
  • plan_preflight_validate.go — deterministic hard checks + user-data vs plan cross-check
  • plan_repair_agent.go — plan rewrite/repair agent
  • plan_issue_triage.go — triage for hard-fixable vs noise/context findings
  • plan_sanitize.go — conservative fail-open plan sanitizer
  • plan_review_agent.go — final non-blocking plan reviewer pass
  • llm_plan_integrity.go — LLM JSON repair + generic integrity pass
  • intelligence.go — multi-phase intelligence + LLM validation
  • explorer.go — agentic file exploration
  • docker_agent.go — Docker/Compose understanding
  • infra_scan.go / cf_infra_scan.go — cloud inventory snapshots
  • openclaw_plan_autofix.go — OpenClaw-specific autofix (HTTPS_URL, compose hints)
  • userdata_autofix.go / userdata_fixups.go / userdata_repair.go — user-data fixups
  • resolve.go — placeholder/binding resolution
  • nodejs_userdata.go — Node.js user-data generation

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func AllPlaceholdersAreProduced

func AllPlaceholdersAreProduced(plan *maker.Plan, placeholders []string) bool

AllPlaceholdersAreProduced returns true when every placeholder token is expected to be provided by an earlier command via `produces` bindings.

func AppendOpenClawDeploymentRequirements

func AppendOpenClawDeploymentRequirements(b *strings.Builder, p *RepoProfile, deep *DeepAnalysis, provider string) bool

func AppendPlanPage

func AppendPlanPage(plan *maker.Plan, page *PlanPage) int

func AppendRulePackDeploymentRequirements added in v0.0.6

func AppendRulePackDeploymentRequirements(b *strings.Builder, ctx RulePackContext) bool

func AppendWordPressDeploymentRequirements

func AppendWordPressDeploymentRequirements(b *strings.Builder, p *RepoProfile, deep *DeepAnalysis) bool

func ApplyDigitalOceanPlanAutofix added in v0.0.6

func ApplyDigitalOceanPlanAutofix(plan *maker.Plan, logf func(string, ...any)) *maker.Plan

ApplyDigitalOceanPlanAutofix runs DO-specific deterministic fixes. Only call this when provider == "digitalocean".

func ApplyEnvVarBindings

func ApplyEnvVarBindings(plan *maker.Plan, envVars map[string]string) *maker.Plan

ApplyEnvVarBindings deterministically resolves env-var placeholders like <DISCORD_BOT_TOKEN> using the actual values the user provided. This avoids relying on the LLM to map them (which fails when the API times out).

func ApplyGenericPlanAutofix

func ApplyGenericPlanAutofix(plan *maker.Plan, logf func(string, ...any), externalBindings ...string) *maker.Plan

ApplyGenericPlanAutofix runs provider-agnostic dedup/cleanup passes. externalBindings are placeholder names provided externally (e.g. user env vars) that should NOT be treated as orphaned even though no command produces them.

func ApplyOpenClawArchitectureDefaults

func ApplyOpenClawArchitectureDefaults(targetProvider string, opts *DeployOptions, p *RepoProfile, deep *DeepAnalysis, arch *ArchitectDecision) bool

func ApplyOpenClawPlanAutofix

func ApplyOpenClawPlanAutofix(plan *maker.Plan, profile *RepoProfile, deep *DeepAnalysis, logf func(string, ...any)) *maker.Plan

func ApplyRulePackArchitectureDefaults added in v0.0.6

func ApplyRulePackArchitectureDefaults(ctx RulePackContext, arch *ArchitectDecision) bool

func ApplyRulePackDeterministicValidation added in v0.0.6

func ApplyRulePackDeterministicValidation(plan *maker.Plan, ctx RulePackContext) deterministicValidation

func ApplyRulePackPlanAutofix added in v0.0.6

func ApplyRulePackPlanAutofix(plan *maker.Plan, ctx RulePackContext, logf func(string, ...any)) *maker.Plan

func ApplySemanticGraphCompilation added in v0.0.6

func ApplySemanticGraphCompilation(plan *maker.Plan, ctx RulePackContext, logf func(string, ...any)) *maker.Plan

ApplySemanticGraphCompilation infers a semantic graph from the current LLM plan and recompiles it into canonical executable commands when the provider path supports it. Unsupported paths intentionally no-op.

func ApplyStaticInfraBindings

func ApplyStaticInfraBindings(plan *maker.Plan, infraSnap *InfraSnapshot) *maker.Plan

ApplyStaticInfraBindings applies only the "static" infrastructure bindings that are always known regardless of whether a new VPC is being created. This includes AMI_ID, ACCOUNT_ID, and REGION which come from the infra scan. This function should be called even when --new-vpc is used.

func ApplyWordPressArchitectureDefaults

func ApplyWordPressArchitectureDefaults(targetProvider string, opts *DeployOptions, p *RepoProfile, deep *DeepAnalysis, arch *ArchitectDecision) bool

func ArchitectPrompt

func ArchitectPrompt(p *RepoProfile) string

ArchitectPrompt builds the prompt for the architect LLM call

func Base64EncodeEC2UserDataScripts

func Base64EncodeEC2UserDataScripts(plan *maker.Plan) *maker.Plan

Base64EncodeEC2UserDataScripts ensures any literal user-data scripts are base64 encoded. This avoids downstream placeholder scanners misinterpreting heredoc markers (e.g. <<EOF) and improves AWS CLI reliability.

func BuildPlanPagePrompt

func BuildPlanPagePrompt(provider string, enrichedPrompt string, currentPlan *maker.Plan, requiredLaunchOps []string, mustFixIssues []string, maxCommands int, formatHint string) string

func BuildPrompt

func BuildPrompt(p *RepoProfile, strat DeployStrategy, archDecision *ArchitectDecision) string

BuildPrompt generates the enriched natural-language prompt that feeds into maker.PlanPrompt. If archDecision is non-nil, it incorporates the LLM architect's reasoning.

func CheckStrictPlanCandidateRegression added in v0.0.6

func CheckStrictPlanCandidateRegression(baseline *maker.Plan, candidate *maker.Plan) error

func ClassifyUserDataIssues

func ClassifyUserDataIssues(issues []string) (userDataIssues, structuralIssues []string)

ClassifyUserDataIssues separates validation issues into user-data-specific and plan-structural categories.

func CompileSemanticGraph added in v0.0.6

func CompileSemanticGraph(baseline *maker.Plan, graph *SemanticGraph, ctx RulePackContext) (*maker.Plan, bool, error)

CompileSemanticGraph turns a provider semantic graph back into an executable plan. The baseline plan remains the source of metadata and user-facing notes.

func FilterRuntimeInjectedTokens added in v0.0.6

func FilterRuntimeInjectedTokens(placeholders []string, envVars []string) []string

FilterRuntimeInjectedTokens removes placeholder tokens that will be resolved at runtime via env var injection (importSecretLikeEnvVarsIntoBindings) or explicit executor bindings (e.g. DIGITALOCEAN_ACCESS_TOKEN). envVars is the list of user-provided env var keys from the deploy request.

func FixEC2UserDataScripts

func FixEC2UserDataScripts(plan *maker.Plan, logf func(string, ...any)) *maker.Plan

FixEC2UserDataScripts decodes base64 user-data in ec2 run-instances, applies common LLM-generated path and command typo corrections, and re-encodes. Runs before validation so deterministic fixes prevent issues from reaching the repair LLM.

func GenerateMissingUserData added in v0.0.6

func GenerateMissingUserData(plan *maker.Plan, logf func(string, ...any)) *maker.Plan

GenerateMissingUserData adds user-data to ec2 run-instances commands that have empty or placeholder user-data but are part of a Docker/ECR deployment. This prevents validation failures that would trigger expensive paged fallback.

func GenerateNodeJSUserData

func GenerateNodeJSUserData(repoURL string, deep *DeepAnalysis, config *UserConfig) string

GenerateNodeJSUserData creates EC2 user-data for native Node.js deployment. This handles any Node.js app: clones repo, installs deps, runs with PM2.

func GetUnresolvedPlaceholders

func GetUnresolvedPlaceholders(plan *maker.Plan) []string

GetUnresolvedPlaceholders returns the list of unresolved placeholder tokens in a plan.

func HasOpenClawCloudFront

func HasOpenClawCloudFront(planJSON string) bool

func HasUnresolvedPlaceholders

func HasUnresolvedPlaceholders(plan *maker.Plan) bool

HasUnresolvedPlaceholders checks if a plan still has unresolved placeholder tokens.

func HydrateSkeleton

func HydrateSkeleton(
	ctx context.Context,
	ask AskFunc,
	clean CleanFunc,
	provider string,
	enrichedPrompt string,
	skeleton *PlanSkeleton,
	logf func(string, ...any),
) (*maker.Plan, error)

HydrateSkeleton fills in the CLI args for each skeleton step via per-step LLM calls. Each call gets: the full skeleton (for context), the specific step to detail, and all commands generated so far (for consistency).

func InferPlanCapabilities added in v0.0.6

func InferPlanCapabilities(provider, enrichedPrompt string, requiredLaunchOps []string) *maker.PlanCapabilities

func IsOpenClawRepo

func IsOpenClawRepo(p *RepoProfile, deep *DeepAnalysis) bool

func IsWordPressRepo

func IsWordPressRepo(p *RepoProfile, deep *DeepAnalysis) bool

func OpenClawArchitectPromptAzure

func OpenClawArchitectPromptAzure() string

func OpenClawArchitectPromptDigitalOcean added in v0.0.6

func OpenClawArchitectPromptDigitalOcean() string

func OpenClawArchitectPromptGCP

func OpenClawArchitectPromptGCP() string

func OpenClawAzureVMPrompt

func OpenClawAzureVMPrompt(p *RepoProfile, deep *DeepAnalysis, opts *DeployOptions) string

func OpenClawComposeHardEnvVars

func OpenClawComposeHardEnvVars() []string

func OpenClawDigitalOceanDropletPrompt added in v0.0.6

func OpenClawDigitalOceanDropletPrompt(p *RepoProfile, deep *DeepAnalysis, opts *DeployOptions) string

func OpenClawGCPComputeEnginePrompt

func OpenClawGCPComputeEnginePrompt(p *RepoProfile, deep *DeepAnalysis, opts *DeployOptions) string

func OpenClawPreferredBootstrapScripts

func OpenClawPreferredBootstrapScripts() []string

func PromptForEnvVarValues

func PromptForEnvVarValues(names []string) (map[string]string, error)

PromptForEnvVarValues prompts the user for values for the given env var names. It is used as a fallback when DeepAnalysis does not provide requiredEnvVars.

func RepairPlanJSONWithLLM

func RepairPlanJSONWithLLM(
	ctx context.Context,
	ask AskFunc,
	clean CleanFunc,
	deploymentIntent string,
	projectSummary string,
	raw string,
	baselinePlanJSON string,
	issues []string,
	requiredLaunchOps []string,
	logf func(string, ...any),
) (*maker.Plan, error)

func RepairUserDataWithLLM

func RepairUserDataWithLLM(
	ctx context.Context,
	plan *maker.Plan,
	issues []string,
	fixes []string,
	ask AskFunc,
	clean CleanFunc,
	logf func(string, ...any),
) (*maker.Plan, error)

RepairUserDataWithLLM performs a targeted micro-repair on user-data scripts inside ec2 run-instances or compute droplet create commands. Instead of sending the full plan to the repair LLM (which causes full rewrites), we extract the script, send ONLY the script + relevant issues, and splice the fix back into the plan. Returns the patched plan and nil error on success. Returns the original plan unchanged if no user-data issues are found or repair fails.

func ResolvePlanPlaceholders

func ResolvePlanPlaceholders(
	ctx context.Context,
	plan *maker.Plan,
	infraSnap *InfraSnapshot,
	ask AskFunc,
	clean CleanFunc,
	logf func(string, ...any),
) (*maker.Plan, []string, error)

ResolvePlanPlaceholders attempts to replace placeholder tokens in the plan with actual values. It first tries to map from the InfraSnapshot, then calls the LLM for any remaining placeholders. Returns the modified plan and a list of any placeholders that could not be resolved.

func RunGenericPlanIntegrityPassWithLLM

func RunGenericPlanIntegrityPassWithLLM(
	ctx context.Context,
	ask AskFunc,
	clean CleanFunc,
	plan *maker.Plan,
	deploymentIntent string,
	projectSummary string,
	requiredLaunchOps []string,
	logf func(string, ...any),
) (*maker.Plan, error)

func SanitizePlan

func SanitizePlan(plan *maker.Plan) *maker.Plan

func SanitizePlanConservative

func SanitizePlanConservative(plan *maker.Plan, profile *RepoProfile, deep *DeepAnalysis, docker *DockerAnalysis, logf func(string, ...any)) *maker.Plan

SanitizePlanConservative applies sanitization in a fail-open way: it evaluates original vs sanitized with deterministic validation and never picks a candidate with more deterministic issues than the original.

func ValidateCommandBindingSequence added in v0.0.6

func ValidateCommandBindingSequence(existingPlan *maker.Plan, commands []maker.Command, envVars []string) []string

func ValidatePlanPageBoundary added in v0.0.6

func ValidatePlanPageBoundary(currentPlan *maker.Plan, page *PlanPage, envVars []string) error

func WordPressEC2Prompt

func WordPressEC2Prompt(p *RepoProfile, opts *DeployOptions) string

WordPressEC2Prompt returns a detailed EC2 deployment prompt for WordPress. Unlike generic EC2, WordPress pulls images from Docker Hub (no ECR).

Types

type ArchitectDecision

type ArchitectDecision struct {
	Provider      string   `json:"provider"`                // aws, cloudflare, gcp, azure, digitalocean
	Method        string   `json:"method"`                  // ecs-fargate, ec2, eks, lambda, s3-cloudfront, cf-pages, cf-workers, cf-containers, do-droplet, do-app-platform
	Reasoning     string   `json:"reasoning"`               // why this architecture
	BuildSteps    []string `json:"buildSteps"`              // how to build it
	RunCmd        string   `json:"runCmd"`                  // simplest way to start it locally
	Notes         []string `json:"notes"`                   // gotchas, warnings
	CpuMemory     string   `json:"cpuMemory"`               // e.g. "256/512", "512/1024", or instance type for EC2
	NeedsALB      bool     `json:"needsAlb"`                // whether to put an ALB in front
	UseAPIGateway bool     `json:"useApiGateway"`           // whether to use API Gateway instead of ALB
	NeedsDB       bool     `json:"needsDb"`                 // whether to provision a managed DB
	DBService     string   `json:"dbService"`               // rds-postgres, elasticache-redis, etc
	EstMonthly    string   `json:"estMonthly"`              // estimated monthly cost e.g. "$15-25"
	CostBreakdown []string `json:"costBreakdown,omitempty"` // per-service cost breakdown
}

ArchitectDecision is the structured JSON response from the architect LLM call

func ParseArchitectDecision

func ParseArchitectDecision(raw string) (*ArchitectDecision, error)

ParseArchitectDecision parses the LLM response into an ArchitectDecision

type AskFunc

type AskFunc func(ctx context.Context, prompt string) (string, error)

AskFunc is the LLM call interface — matches ai.Client.AskPrompt signature

type CFInfraSnapshot

type CFInfraSnapshot struct {
	AccountID     string   `json:"accountId,omitempty"`
	Workers       []string `json:"workers,omitempty"`       // existing worker names
	PagesProjects []string `json:"pagesProjects,omitempty"` // existing pages projects
	KVNamespaces  []string `json:"kvNamespaces,omitempty"`  // existing KV namespaces
	D1Databases   []string `json:"d1Databases,omitempty"`   // existing D1 databases
	R2Buckets     []string `json:"r2Buckets,omitempty"`     // existing R2 buckets
}

CFInfraSnapshot holds existing Cloudflare resources

func ScanCFInfra

func ScanCFInfra(ctx context.Context, logf func(string, ...any)) *CFInfraSnapshot

ScanCFInfra queries the Cloudflare account for existing resources via wrangler

func (*CFInfraSnapshot) FormatCFForPrompt

func (s *CFInfraSnapshot) FormatCFForPrompt() string

FormatCFForPrompt formats the CF infra snapshot for LLM context

type CleanFunc

type CleanFunc func(response string) string

CleanFunc strips markdown fences from LLM JSON responses

type DODropletInfo added in v0.0.6

type DODropletInfo struct {
	ID     string `json:"id"`
	Name   string `json:"name"`
	Region string `json:"region"`
	Status string `json:"status"`
}

DODropletInfo is a droplet summary

type DOFirewall added in v0.0.6

type DOFirewall struct {
	ID   string `json:"id"`
	Name string `json:"name"`
}

DOFirewall is a firewall summary

type DOInfraSnapshot added in v0.0.6

type DOInfraSnapshot struct {
	Droplets       []DODropletInfo `json:"droplets,omitempty"`
	SSHKeys        []DOSSHKeyInfo  `json:"sshKeys,omitempty"`
	LocalSSHPubKey string          `json:"localSshPubKey,omitempty"` // best local ~/.ssh/*.pub path
	Registries     []string        `json:"registries,omitempty"`
	Firewalls      []DOFirewall    `json:"firewalls,omitempty"`
	ReservedIPs    []string        `json:"reservedIps,omitempty"`
	VPCs           []DOVPCInfo     `json:"vpcs,omitempty"`
	Summary        string          `json:"summary"`
}

DOInfraSnapshot holds existing Digital Ocean infrastructure

func ScanDOInfra added in v0.0.6

func ScanDOInfra(ctx context.Context, apiToken string, logf func(string, ...any)) *DOInfraSnapshot

ScanDOInfra queries the DO account via doctl to see what's already there. Fails gracefully — returns partial snapshot on individual command failures.

func (*DOInfraSnapshot) FormatForPrompt added in v0.0.6

func (s *DOInfraSnapshot) FormatForPrompt() string

FormatForPrompt formats the DO infra snapshot for the LLM prompt

type DOSSHKeyInfo added in v0.0.6

type DOSSHKeyInfo struct {
	ID   string `json:"id"`
	Name string `json:"name"`
}

DOSSHKeyInfo is an SSH key summary

type DOVPCInfo added in v0.0.6

type DOVPCInfo struct {
	ID     string `json:"id"`
	Name   string `json:"name"`
	Region string `json:"region"`
}

DOVPCInfo is a VPC summary

type DeepAnalysis

type DeepAnalysis struct {
	AppDescription string   `json:"appDescription"` // what does this app do
	Services       []string `json:"services"`       // list of services/components
	ExternalDeps   []string `json:"externalDeps"`   // external APIs, databases, etc
	BuildPipeline  string   `json:"buildPipeline"`  // how to actually build this thing
	RunLocally     string   `json:"runLocally"`     // simplest way to run locally
	Complexity     string   `json:"complexity"`     // simple, moderate, complex
	Concerns       []string `json:"concerns"`       // things that could go wrong

	// Node.js app characteristics (detected from README and code)
	ListeningPort int    `json:"listeningPort"` // port the app listens on
	StartCommand  string `json:"startCommand"`  // how to start: "npm start", "node index.js"
	BuildCommand  string `json:"buildCommand"`  // build step if needed: "npm run build"
	NodeVersion   string `json:"nodeVersion"`   // required Node version

	// Config requirements (extracted from README and .env files)
	RequiredEnvVars []EnvVarSpec `json:"requiredEnvVars"` // MUST have values to run
	OptionalEnvVars []EnvVarSpec `json:"optionalEnvVars"` // nice to have, has defaults

	// Health verification
	HealthEndpoint string `json:"healthEndpoint"` // e.g., "/health", "/api/status"
	ExposesHTTP    bool   `json:"exposesHTTP"`    // does it serve HTTP?

	// Deployment method
	PreferDocker  bool   `json:"preferDocker"`  // true if Dockerfile exists and is recommended
	GlobalInstall string `json:"globalInstall"` // e.g., "npm install -g appname"
}

DeepAnalysis is the LLM's understanding of what the app actually does

type DeployOptions

type DeployOptions struct {
	Target       string // fargate, ec2, eks
	InstanceType string // for ec2: t3.small, t3.medium, etc.
	NewVPC       bool   // create new VPC instead of using default
	DeployID     string // run-specific id for unique resource naming
	DOToken      string // DigitalOcean API token for infra scan
	HetznerToken string // Hetzner Cloud API token for infra scan
}

DeployOptions contains user-specified deployment preferences

type DeployStrategy

type DeployStrategy struct {
	Provider  string // aws, cloudflare
	Method    string // ecs-fargate, ec2, lambda, s3-cloudfront, cf-pages, cf-workers, cf-containers
	Region    string
	Reasoning string // LLM's reasoning for the choice
}

DeployStrategy controls how we deploy

func DefaultStrategy

func DefaultStrategy(p *RepoProfile) DeployStrategy

DefaultStrategy picks the best deployment method based on the repo profile

func StrategyFromArchitect

func StrategyFromArchitect(d *ArchitectDecision) DeployStrategy

StrategyFromArchitect converts an ArchitectDecision into a DeployStrategy

type DockerAnalysis

type DockerAnalysis struct {
	HasDockerfile       bool     `json:"hasDockerfile"`
	HasCompose          bool     `json:"hasCompose"`
	BuildUsesMultiStage bool     `json:"buildUsesMultiStage"`
	HasPlatformPin      bool     `json:"hasPlatformPin"`
	PlatformPins        []string `json:"platformPins,omitempty"`
	ComposeServices     []string `json:"composeServices,omitempty"`
	ExposedPorts        []int    `json:"exposedPorts,omitempty"`
	PublishedPorts      []int    `json:"publishedPorts,omitempty"`
	PrimaryPort         int      `json:"primaryPort,omitempty"`
	HasHealthcheck      bool     `json:"hasHealthcheck"`
	HealthcheckHint     string   `json:"healthcheckHint,omitempty"`
	VolumeMounts        []string `json:"volumeMounts,omitempty"`
	EnvFiles            []string `json:"envFiles,omitempty"`
	ReferencedEnvVars   []string `json:"referencedEnvVars,omitempty"`
	HardRequiredEnvVars []string `json:"hardRequiredEnvVars,omitempty"`
	BuildCommand        string   `json:"buildCommand,omitempty"`
	RunCommand          string   `json:"runCommand,omitempty"`
	Warnings            []string `json:"warnings,omitempty"`
}

func AnalyzeDockerAgent

func AnalyzeDockerAgent(profile *RepoProfile) *DockerAnalysis

func (*DockerAnalysis) FormatForPrompt

func (d *DockerAnalysis) FormatForPrompt() string

type EnvVarSpec

type EnvVarSpec struct {
	Name        string `json:"name"`
	Description string `json:"description"`
	Required    bool   `json:"required"`
	Default     string `json:"default"` // default value if known
	Example     string `json:"example"`
}

EnvVarSpec describes a required or optional environment variable

type ExplorationResult

type ExplorationResult struct {
	FilesRead map[string]string // all files read during exploration
	Rounds    int               // how many exploration rounds
	Analysis  string            // LLM's analysis after reading everything
}

ExplorationResult is the output of the agentic exploration

func ExploreRepo

func ExploreRepo(ctx context.Context, profile *RepoProfile, ask AskFunc, clean CleanFunc, logf func(string, ...any)) (*ExplorationResult, error)

ExploreRepo runs agentic file exploration: LLM sees the tree → requests files → we read them → LLM requests more → done

type FileRequest

type FileRequest struct {
	Files    []string `json:"files"`    // files it wants to read
	Reason   string   `json:"reason"`   // why it needs them
	Done     bool     `json:"done"`     // true = has enough context
	Analysis string   `json:"analysis"` // partial analysis so far (when done=true)
}

FileRequest is what the LLM asks for during exploration

type HetznerFirewall added in v0.0.6

type HetznerFirewall struct {
	ID   string `json:"id"`
	Name string `json:"name"`
}

HetznerFirewall is a firewall summary

type HetznerInfraSnapshot added in v0.0.6

type HetznerInfraSnapshot struct {
	Servers     []HetznerServerInfo  `json:"servers,omitempty"`
	SSHKeys     []HetznerSSHKeyInfo  `json:"sshKeys,omitempty"`
	Firewalls   []HetznerFirewall    `json:"firewalls,omitempty"`
	FloatingIPs []string             `json:"floatingIps,omitempty"`
	Networks    []HetznerNetworkInfo `json:"networks,omitempty"`
	Volumes     []HetznerVolumeInfo  `json:"volumes,omitempty"`
	Summary     string               `json:"summary"`
}

HetznerInfraSnapshot holds existing Hetzner Cloud infrastructure

func ScanHetznerInfra added in v0.0.6

func ScanHetznerInfra(ctx context.Context, apiToken string, logf func(string, ...any)) *HetznerInfraSnapshot

ScanHetznerInfra queries the Hetzner account via hcloud CLI to see what's already there. Fails gracefully: returns partial snapshot on individual command failures.

func (*HetznerInfraSnapshot) FormatForPrompt added in v0.0.6

func (s *HetznerInfraSnapshot) FormatForPrompt() string

FormatForPrompt formats the Hetzner infra snapshot for the LLM prompt

type HetznerNetworkInfo added in v0.0.6

type HetznerNetworkInfo struct {
	ID      string `json:"id"`
	Name    string `json:"name"`
	IPRange string `json:"ipRange"`
}

HetznerNetworkInfo is a network summary

type HetznerSSHKeyInfo added in v0.0.6

type HetznerSSHKeyInfo struct {
	ID   string `json:"id"`
	Name string `json:"name"`
}

HetznerSSHKeyInfo is an SSH key summary

type HetznerServerInfo added in v0.0.6

type HetznerServerInfo struct {
	ID       string `json:"id"`
	Name     string `json:"name"`
	Location string `json:"location"`
	Status   string `json:"status"`
}

HetznerServerInfo is a server summary

type HetznerVolumeInfo added in v0.0.6

type HetznerVolumeInfo struct {
	ID       string `json:"id"`
	Name     string `json:"name"`
	Size     int    `json:"size"`
	Location string `json:"location"`
}

HetznerVolumeInfo is a volume summary

type InfraSnapshot

type InfraSnapshot struct {
	AccountID                  string   `json:"accountId,omitempty"`
	Region                     string   `json:"region"`
	VPC                        *VPCInfo `json:"vpc,omitempty"`
	ECRRepos                   []string `json:"ecrRepos,omitempty"`                   // existing ECR repos
	CloudFrontDists            []string `json:"cloudFrontDists,omitempty"`            // existing CloudFront distribution domains
	LightsailInstances         []string `json:"lightsailInstances,omitempty"`         // existing Lightsail instances
	LightsailContainerServices []string `json:"lightsailContainerServices,omitempty"` // existing Lightsail container services
	LightsailDistributions     []string `json:"lightsailDistributions,omitempty"`     // existing Lightsail CDN distributions
	ECSClusters                []string `json:"ecsClusters,omitempty"`                // existing ECS clusters
	ALBs                       []string `json:"albs,omitempty"`                       // existing ALBs
	RDSInstances               []string `json:"rdsInstances,omitempty"`               // existing RDS instances
	SecurityGroups             []SGInfo `json:"securityGroups,omitempty"`             // existing SGs in default VPC
	LatestAMI                  string   `json:"latestAmi,omitempty"`                  // latest Amazon Linux 2023 AMI ID
	Summary                    string   `json:"summary"`
}

InfraSnapshot is a snapshot of existing AWS infrastructure

func ScanInfra

func ScanInfra(ctx context.Context, profile, region string, logf func(string, ...any)) *InfraSnapshot

ScanInfra queries the AWS account to see what's already there. Uses the provided profile and region. Fails gracefully on permission errors.

func (*InfraSnapshot) FormatForPrompt

func (s *InfraSnapshot) FormatForPrompt() string

FormatForPrompt formats the infra snapshot as text for the LLM prompt

type IntelligenceResult

type IntelligenceResult struct {
	Exploration      *ExplorationResult    `json:"exploration,omitempty"`
	DeepAnalysis     *DeepAnalysis         `json:"deepAnalysis"`
	Docker           *DockerAnalysis       `json:"docker,omitempty"`
	Preflight        *PreflightReport      `json:"preflight,omitempty"`
	InfraSnap        *InfraSnapshot        `json:"infraSnapshot,omitempty"`
	CFInfraSnap      *CFInfraSnapshot      `json:"cfInfraSnapshot,omitempty"`
	DOInfraSnap      *DOInfraSnapshot      `json:"doInfraSnapshot,omitempty"`
	HetznerInfraSnap *HetznerInfraSnapshot `json:"hetznerInfraSnapshot,omitempty"`
	Architecture     *ArchitectDecision    `json:"architecture"`
	Validation       *PlanValidation       `json:"validation,omitempty"`
	// final enriched prompt for maker pipeline
	EnrichedPrompt string `json:"enrichedPrompt"`
}

IntelligenceResult is the final output of the multi-phase reasoning pipeline

func RunIntelligence

func RunIntelligence(ctx context.Context, profile *RepoProfile, ask AskFunc, clean CleanFunc, debug bool, targetProvider, awsProfile, awsRegion string, opts *DeployOptions, logf func(string, ...any)) (*IntelligenceResult, error)

RunIntelligence executes the multi-phase recursive reasoning pipeline. Phase 0: Agentic file exploration (LLM requests files it needs) Phase 1: Deep Understanding (LLM analyzes all gathered context) Phase 1.5: AWS infra scan (query account for existing resources) Phase 2: Architecture Decision + Cost Estimation (LLM picks best option) Both phases feed into the final enriched prompt for the maker plan generator.

type PlanPage

type PlanPage struct {
	Done     bool            `json:"done"`
	Commands []maker.Command `json:"commands"`
	Summary  string          `json:"summary,omitempty"`
	Notes    []string        `json:"notes,omitempty"`
}

PlanPage is a paginated chunk of commands used to build a full maker.Plan incrementally. It is intentionally small to avoid LLM output truncation.

func ParsePlanPage

func ParsePlanPage(cleanedJSON string) (*PlanPage, error)

func RepairPlanPageWithLLM

func RepairPlanPageWithLLM(
	ctx context.Context,
	ask AskFunc,
	clean CleanFunc,
	provider string,
	deploymentIntent string,
	projectSummary string,
	raw string,
	formatHint string,
	logf func(string, ...any),
) (*PlanPage, string, error)

type PlanRepairAgent

type PlanRepairAgent struct {
	// contains filtered or unexported fields
}

func NewPlanRepairAgent

func NewPlanRepairAgent(ask AskFunc, clean CleanFunc, logf func(string, ...any)) *PlanRepairAgent

func (*PlanRepairAgent) Repair

type PlanRepairContext

type PlanRepairContext struct {
	Provider   string
	Method     string
	RepoURL    string
	LLMContext string

	GCPProject          string
	AzureSubscriptionID string
	CloudflareAccountID string

	// App/runtime hints (kept compact)
	Ports               []int
	ComposeHardEnvVars  []string
	RequiredEnvVarNames []string
	// RequiredLaunchOps constrains the repair to include at least one workload "launch" step.
	// Each entry is "<service> <operation>" (e.g. "ec2 run-instances", "ecs create-service").
	RequiredLaunchOps []string

	// AWS infra hints (optional)
	Region  string
	Account string
	VPCID   string
	Subnets []string
	AMIID   string
}

type PlanReviewAgent

type PlanReviewAgent struct {
	// contains filtered or unexported fields
}

func NewPlanReviewAgent

func NewPlanReviewAgent(ask AskFunc, clean CleanFunc, logf func(string, ...any)) *PlanReviewAgent

func (*PlanReviewAgent) Review

func (a *PlanReviewAgent) Review(ctx context.Context, planJSON string, c PlanReviewContext) (string, error)

type PlanReviewContext

type PlanReviewContext struct {
	Provider                  string
	Method                    string
	RepoURL                   string
	LLMContext                string
	ProjectSummary            string
	ProjectCharacteristics    []string
	RequiredLaunchOps         []string
	IsOpenClaw                bool
	OpenClawCloudFrontMissing bool
	IsWordPress               bool
	Issues                    []string
	Fixes                     []string
	Warnings                  []string
}

type PlanSkeleton

type PlanSkeleton struct {
	Steps        []SkeletonStep       `json:"steps"`
	Notes        []string             `json:"notes,omitempty"`
	Capabilities SkeletonCapabilities `json:"capabilities,omitempty"`
}

PlanSkeleton is the high-level structure of a deployment plan. Generated in a single LLM call — just service/operation pairs, no full args.

func GeneratePlanSkeleton

func GeneratePlanSkeleton(
	ctx context.Context,
	ask AskFunc,
	clean CleanFunc,
	provider string,
	enrichedPrompt string,
	requiredLaunchOps []string,
	logf func(string, ...any),
) (*PlanSkeleton, error)

GeneratePlanSkeleton asks the LLM to produce only the plan structure. No CLI args, no JSON payloads — just the ordered list of service/operation pairs with placeholder dependency wiring.

func TopologicalSortSkeleton added in v0.0.6

func TopologicalSortSkeleton(skeleton *PlanSkeleton) (*PlanSkeleton, error)

TopologicalSortSkeleton reorders skeleton steps to satisfy dependency constraints. Uses Kahn's algorithm to ensure steps that produce placeholders come before steps that depend on those placeholders. Returns error if cycle detected.

type PlanValidation

type PlanValidation struct {
	IsValid                bool     `json:"isValid"`
	Issues                 []string `json:"issues"`                 // problems found
	Fixes                  []string `json:"fixes"`                  // suggested fixes
	Warnings               []string `json:"warnings"`               // non-blocking warnings
	UnresolvedPlaceholders []string `json:"unresolvedPlaceholders"` // placeholders that need resolution
}

PlanValidation is the LLM's review of its own generated plan

func CheckBulkRepairInvariants

func CheckBulkRepairInvariants(plan *maker.Plan, profile *RepoProfile, deep *DeepAnalysis, runtimeEnvKeys []string) *PlanValidation

func CheckOpenClawBulkInvariants

func CheckOpenClawBulkInvariants(plan *maker.Plan, profile *RepoProfile, deep *DeepAnalysis, runtimeEnvKeys []string) *PlanValidation

func DeterministicValidatePlan

func DeterministicValidatePlan(planJSON string, profile *RepoProfile, deep *DeepAnalysis, docker *DockerAnalysis, runtimeEnvKeys []string) *PlanValidation

DeterministicValidatePlan runs only the deterministic validation checks and returns a PlanValidation. This is used for incremental / checkpointed plan generation to avoid repeated LLM validation calls.

func FilterDOValidationNoise added in v0.0.6

func FilterDOValidationNoise(v *PlanValidation, logf func(string, ...any)) *PlanValidation

FilterDOValidationNoise removes LLM validator false positives for DO plans. The executor supports both doctl and docker commands, but the LLM validator doesn't know this and flags docker build/push as broken.

func ValidatePlan

func ValidatePlan(ctx context.Context, planJSON string, profile *RepoProfile, deep *DeepAnalysis, docker *DockerAnalysis, requireDockerCommandsInPlan bool, ask AskFunc, clean CleanFunc, logf func(string, ...any)) (*PlanValidation, string, error)

ValidatePlan runs the LLM validation phase on a generated plan. Call this AFTER the maker plan is generated. Returns validation result and an optional revised prompt if issues were found.

func ValidatePlanDeterministicFinal added in v0.0.6

func ValidatePlanDeterministicFinal(plan *maker.Plan, p *RepoProfile, deep *DeepAnalysis, docker *DockerAnalysis, runtimeEnvKeys []string) *PlanValidation

ValidatePlanDeterministicFinal re-runs deterministic validation on the final post-review/post-autofix plan so late mutations cannot silently reintroduce broken DO firewall shapes, missing OpenClaw env vars, or bad user-data.

type PreflightReport

type PreflightReport struct {
	PackageManager     string   `json:"packageManager"`
	IsMonorepo         bool     `json:"isMonorepo"`
	LockFiles          []string `json:"lockFiles,omitempty"`
	BootstrapScripts   []string `json:"bootstrapScripts,omitempty"`
	EnvExampleFiles    []string `json:"envExampleFiles,omitempty"`
	MigrationHints     []string `json:"migrationHints,omitempty"`
	NativeDeps         []string `json:"nativeDeps,omitempty"`
	BuildOutputDir     string   `json:"buildOutputDir,omitempty"`
	IsStaticSite       bool     `json:"isStaticSite"`
	ComposeHardEnvVars []string `json:"composeHardEnvVars,omitempty"`
	Warnings           []string `json:"warnings,omitempty"`
}

func BuildPreflightReport

func BuildPreflightReport(p *RepoProfile, docker *DockerAnalysis, deep *DeepAnalysis) *PreflightReport

func (*PreflightReport) FormatForPrompt

func (r *PreflightReport) FormatForPrompt() string

type RepairIssueTriage

type RepairIssueTriage struct {
	Hard          *PlanValidation
	LikelyNoise   []string
	ContextNeeded []string
}

func TriageValidationForRepair

func TriageValidationForRepair(v *PlanValidation) RepairIssueTriage

type RepoProfile

type RepoProfile struct {
	RepoURL          string            `json:"repoUrl"`
	ClonePath        string            `json:"clonePath"`
	Language         string            `json:"language"`       // go, python, node, rust, java, etc
	Framework        string            `json:"framework"`      // express, flask, fastapi, gin, fiber, nextjs, etc
	PackageManager   string            `json:"packageManager"` // npm, pnpm, yarn, bun, pip, cargo, go
	IsMonorepo       bool              `json:"isMonorepo"`
	HasDocker        bool              `json:"hasDocker"`
	HasCompose       bool              `json:"hasCompose"`                 // docker-compose.yml
	DeployHints      []string          `json:"deployHints"`                // fly.toml, render.yaml, etc
	BootstrapScripts []string          `json:"bootstrapScripts,omitempty"` // docker-setup.sh, setup scripts, onboard scripts
	EnvExampleFiles  []string          `json:"envExampleFiles,omitempty"`  // .env.example, etc
	MigrationHints   []string          `json:"migrationHints,omitempty"`   // detected migration tooling/files
	NativeDeps       []string          `json:"nativeDeps,omitempty"`       // node native deps that often need OS packages
	BuildOutputDir   string            `json:"buildOutputDir,omitempty"`   // dist/build/out/.next
	IsStaticSite     bool              `json:"isStaticSite"`               // likely static bundle deployable
	LockFiles        []string          `json:"lockFiles,omitempty"`        // pnpm-lock.yaml, yarn.lock, etc
	Ports            []int             `json:"ports"`
	EnvVars          []string          `json:"envVars"`    // required env vars detected
	EntryPoint       string            `json:"entryPoint"` // main.go, app.py, index.js, etc
	BuildCmd         string            `json:"buildCmd"`
	StartCmd         string            `json:"startCmd"`
	HasDB            bool              `json:"hasDb"`
	DBType           string            `json:"dbType"` // postgres, mysql, redis, mongo, etc
	Summary          string            `json:"summary"`
	KeyFiles         map[string]string `json:"keyFiles"` // filename → content (capped)
	FileTree         string            `json:"fileTree"` // top-level directory listing
}

RepoProfile is the result of analyzing a git repo

func Analyze

func Analyze(dir string) (*RepoProfile, error)

Analyze inspects a local directory

func CloneAndAnalyze

func CloneAndAnalyze(ctx context.Context, repoURL string) (*RepoProfile, error)

CloneAndAnalyze clones a repo and returns a profile

type RulePack added in v0.0.6

type RulePack struct {
	Name                      string
	Scope                     rulePackScope
	Matches                   func(RulePackContext) bool
	ApplyArchitectureDefaults func(RulePackContext, *ArchitectDecision) bool
	AppendRequirements        func(RulePackContext, *strings.Builder) bool
	ApplyPlanAutofix          func(*maker.Plan, RulePackContext, func(string, ...any)) *maker.Plan
	ValidatePlan              func(*maker.Plan, RulePackContext) deterministicValidation
}

type RulePackContext added in v0.0.6

type RulePackContext struct {
	TargetProvider string
	PlanProvider   string
	Options        *DeployOptions
	Profile        *RepoProfile
	Deep           *DeepAnalysis
	Docker         *DockerAnalysis
	AppPorts       []int
}

type SGInfo

type SGInfo struct {
	ID   string `json:"id"`
	Name string `json:"name"`
}

SGInfo is a security group summary

type SemanticGraph added in v0.0.6

type SemanticGraph struct {
	Provider     string              `json:"provider"`
	AppKind      string              `json:"app_kind,omitempty"`
	RuntimeModel string              `json:"runtime_model,omitempty"`
	Nodes        []SemanticGraphNode `json:"nodes"`
}

SemanticGraph is the provider/app/runtime graph inferred from an LLM plan before final executable command compilation.

func BuildSemanticGraph added in v0.0.6

func BuildSemanticGraph(plan *maker.Plan, ctx RulePackContext) (*SemanticGraph, bool, error)

BuildSemanticGraph infers a semantic graph from a provider-specific command plan while preserving the LLM as the source of deploy intent.

type SemanticGraphNode added in v0.0.6

type SemanticGraphNode struct {
	ID                 string                          `json:"id"`
	Kind               string                          `json:"kind"`
	Name               string                          `json:"name,omitempty"`
	Reason             string                          `json:"reason,omitempty"`
	DependsOn          []string                        `json:"depends_on,omitempty"`
	Outputs            map[string]string               `json:"outputs,omitempty"`
	Attributes         map[string]string               `json:"attributes,omitempty"`
	SSHKey             *semanticSSHKeySpec             `json:"ssh_key,omitempty"`
	Registry           *semanticRegistrySpec           `json:"registry,omitempty"`
	Droplet            *semanticDropletSpec            `json:"droplet,omitempty"`
	ContainerImage     *semanticContainerImageSpec     `json:"container_image,omitempty"`
	FirewallAttachment *semanticFirewallAttachmentSpec `json:"firewall_attachment,omitempty"`
	Firewall           *doFirewallSpec                 `json:"firewall,omitempty"`
	Bootstrap          *openClawDOBootstrapSpec        `json:"bootstrap,omitempty"`
	AppProxy           *digitalOceanAppPlatformProxy   `json:"app_proxy,omitempty"`
}

SemanticGraphNode is one semantic deployment step. Node payloads are typed enough for provider compilation but still broad enough to preserve generic repo-driven planning.

type SkeletonCapabilities added in v0.0.6

type SkeletonCapabilities struct {
	Provider       string   `json:"provider,omitempty"`
	AppKind        string   `json:"app_kind,omitempty"`
	RuntimeModel   string   `json:"runtime_model,omitempty"`
	RequiredSteps  []string `json:"required_steps,omitempty"`
	ForbiddenSteps []string `json:"forbidden_steps,omitempty"`
	PreferredPorts []string `json:"preferred_ports,omitempty"`
	RequiredEnv    []string `json:"required_env,omitempty"`
	ExecutionNotes []string `json:"execution_notes,omitempty"`
}

type SkeletonStep

type SkeletonStep struct {
	Service   string   `json:"service"`              // e.g. "iam", "ec2", "elbv2", "ssm", "secretsmanager"
	Operation string   `json:"operation"`            // e.g. "create-role", "run-instances"
	Reason    string   `json:"reason"`               // why this step exists
	Produces  []string `json:"produces,omitempty"`   // placeholder names this step outputs (e.g. ["ROLE_ARN"])
	DependsOn []string `json:"depends_on,omitempty"` // placeholder names required from earlier steps
}

SkeletonStep is one step in the skeleton — intentionally minimal.

type UserConfig

type UserConfig struct {
	EnvVars      map[string]string // all env vars (required + optional with values)
	AppPort      int               // confirmed listening port
	DeployMode   string            // docker or native
	StartCommand string            // confirmed start command
	BuildCommand string            // build command if needed
}

UserConfig holds user-provided deployment configuration

func DefaultUserConfig

func DefaultUserConfig(deep *DeepAnalysis, profile *RepoProfile) *UserConfig

DefaultUserConfig returns a default config when no prompting is needed

func PromptForConfig

func PromptForConfig(deep *DeepAnalysis, profile *RepoProfile) (*UserConfig, error)

PromptForConfig collects required configuration from user before deployment

type VPCInfo

type VPCInfo struct {
	VPCID     string   `json:"vpcId"`
	Subnets   []string `json:"subnets"` // subnet IDs
	IsDefault bool     `json:"isDefault"`
}

VPCInfo is the default VPC + subnets info

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL