> ## Documentation Index
> Fetch the complete documentation index at: https://docs.ubiquex.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Multi-Stack Workspaces

> Compile multiple XCL stacks in dependency order with ubx compile --all.

A workspace is a directory containing multiple XCL stacks. `ubx compile --all` discovers every stack in the workspace, resolves the dependency order from `@name` cross-stack references, and compiles each stack in sequence.

## Directory layout

### Flat workspace

The simplest layout is a flat directory with one subdirectory per stack:

```
workspace/
  networking/         ← stack 1
    stack.xcl
    input.xcl
    output.xcl
  cluster/            ← stack 2 (depends on @networking)
    stack.xcl
    output.xcl
  addons/             ← stack 3 (depends on @cluster)
    stack.xcl
    output.xcl
```

### Nested workspace

Stacks can be at any depth. Every directory containing `.xcl` files is treated as an independent stack:

```
workspace/
  infra/
    networking/       ← stack (exports vpc_id)
      stack.xcl
      input.xcl
      output.xcl
    cluster/          ← stack (depends on @networking)
      stack.xcl
      output.xcl
  apps/
    gitops/           ← stack (exports clone_url)
      stack.xcl
      output.xcl
    addons/           ← stack (depends on @gitops)
      stack.xcl
      output.xcl
```

## Cross-stack references

Use `@stackName.outputName` to reference an output from another stack:

```xcl theme={"theme":"css-variables"}
// cluster/stack.xcl
stack "cluster" {
    eks = aws.eks.Cluster {
        vpc_id     = @networking.vpc_id
        subnet_ids = @networking.subnet_ids
    }
}
```

The stack name in `@name` is the **directory basename** of the dependency.

## Sibling discovery rule

When the compiler encounters `@networking`, it looks for the networking stack at:

```
<parent of current stack directory>/networking/
```

For a flat workspace where `cluster/` and `networking/` are siblings, this resolves correctly:

* `cluster/` → parent is `workspace/` → looks for `workspace/networking/` ✓

For a nested workspace, the same-parent rule applies:

* `infra/cluster/` → parent is `infra/` → looks for `infra/networking/` ✓
* `apps/addons/` → parent is `apps/` → looks for `apps/gitops/` ✓

**Cross-domain references are not supported** in the current version. An `apps/addons` stack cannot reference `@networking` from `infra/networking` — the compiler would look for `apps/networking/` which doesn't exist.

## Compiling a workspace

```sh theme={"theme":"css-variables"}
# Compile all stacks in the current directory (recursive):
ubx compile --all .

# Compile all stacks in a specific directory:
ubx compile --all ./workspace
```

Output:

```
● Resolving  dependency graph
             networking/ → cluster/ → addons/
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
● networking/         (1/3)
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
● Typecheck  2 file(s)
● IR         building…
● Output     networking/.ubx/__main__.py

✓  compiled 2 file(s) → networking/.ubx/__main__.py
...
✓  all 3 stacks compiled
```

## Dependency resolution

The compiler builds a dependency graph by:

1. Parsing each stack's `.xcl` files (lex + parse — no typechecking yet)
2. Scanning for `@name` cross-stack references using the parsed AST
3. Building an adjacency map: stack → \[dependent stacks]
4. Topological sort (DFS-based) to determine compilation order

Dependencies compile before the stacks that depend on them, so sibling output names are available for validation when a dependent stack is typechecked.

## Circular dependency detection

If stacks reference each other in a cycle, the compiler reports a clear error and aborts:

```
✗  circular dependency: networking → cluster → networking
```

## Duplicate stack names

Two stacks in different subdirectories cannot have the same directory name — this would make `@name` references ambiguous:

```
✗  ambiguous stack name "@networking" — found at /workspace/infra/networking and /workspace/staging/networking, rename one directory to resolve
```

Rename one of the conflicting directories to resolve the ambiguity.

## Partial failure

If a stack fails to compile (parse errors, typecheck errors, or output errors), the workspace compile continues to attempt the remaining stacks. A summary is printed at the end:

```
✗  2/3 stacks failed: cluster, addons
```

Individual stack errors are printed inline as each stack is processed.

## Example: three-stack workspace

```
workspace/
  networking/
    input.xcl
    stack.xcl
    output.xcl
  cluster/
    stack.xcl
    output.xcl
  addons/
    stack.xcl
    output.xcl
```

```xcl theme={"theme":"css-variables"}
// networking/input.xcl
input "networking" {
    vpc_cidr: string = "10.0.0.0/16"
    azs:      list(string)
}

// networking/stack.xcl
stack "networking" {
    vpc = aws.ec2.Vpc {
        cidr_block = input.vpc_cidr
    }
}

// networking/output.xcl
output "networking" {
    vpc_id = vpc.id
}
```

```xcl theme={"theme":"css-variables"}
// cluster/stack.xcl
stack "cluster" {
    eks = aws.eks.Cluster {
        vpc_id = @networking.vpc_id
    }
}

// cluster/output.xcl
output "cluster" {
    endpoint = eks.endpoint
}
```

```xcl theme={"theme":"css-variables"}
// addons/stack.xcl
stack "addons" {
    argocd = helm.Release {
        cluster_endpoint = @cluster.endpoint
    }
}

// addons/output.xcl
output "addons" {
    status = argocd.status
}
```

```sh theme={"theme":"css-variables"}
ubx compile --all ./workspace
# Compiles: networking → cluster → addons
```
