# Synapse Template System Architecture

## Overview

The Synapse CLI uses a Mustache-based templating system for rendering RPC responses into human-readable output. The system features:

- **Mustache templating** - Logic-less templates for response rendering
- **Schema-driven generation** - Auto-generate templates from method schemas
- **Hierarchical resolution** - Search path priority for template lookup

## Template Flow

```
Request → Parse (CLI.Parse) → Submit (Transport) → Response
                                                      ↓
                                             Template Render
                                                      ↓
                                                   Output
```

The templating system sits at the end of the request pipeline, transforming JSON responses into formatted text output.

## Key Modules

### 1. Renderer.hs (268 lines)

Core template rendering infrastructure:

- **Template cache** - `IORef`-based cache to avoid recompilation
- **Search path resolution** - Multi-location template lookup
- **Mustache compilation** - Template parsing and execution
- **`prettyValue` fallback** - Default JSON pretty-printing when templates unavailable

Key functions:
| Function | Line | Purpose |
|----------|------|---------|
| `newTemplateCache` | 96 | Initialize empty template cache |
| `resolveTemplate` | 130 | Search paths for template file |
| `renderValue` | 207 | Execute template against JSON value |

### 2. TemplateGen.hs (328 lines)

Schema-to-template code generation:

- **Catamorphism-based** - Walks `SchemaF` algebra to generate templates
- **Per-method templates** - One `.mustache` file per RPC method
- **`--generate-templates` flag** - CLI invocation for template generation

Key functions:
| Function | Line | Purpose |
|----------|------|---------|
| `generateAllTemplates` | 175 | Generate templates for all methods |
| `schemaToMustache` | 221 | Convert JSON Schema to Mustache template |

### 3. Main.hs Integration

Response dispatch in the CLI entry point:

- `printResult` (line 422) - Dispatch based on `--json`/`--raw` flags
- `renderItem` - Streaming item rendering callback
- Callback-based architecture to render items as they arrive

## Template Storage

### Search Path Priority (highest first)

1. **Local project**: `.substrate/templates/{namespace}/{method}.mustache`
2. **User config**: `~/.config/synapse/templates/{namespace}/{method}.mustache`
3. **Built-in defaults**: Compiled-in templates

### Resolution Algorithm

For a method `arbor.tree_get`, resolution tries in order:

1. **Exact match**: `{path}/arbor/tree_get.mustache`
2. **Namespace fallback**: `{path}/arbor/default.mustache`
3. **Global fallback**: `{path}/default.mustache`

First match wins; if no template found, falls back to `prettyValue` JSON formatting.

## Dead Code Analysis

### OutputMode Enum (Renderer.hs:75-79)

```haskell
data OutputMode
  = ModeTemplate  -- Render via mustache
  | ModeJson      -- Full JSON output
  | ModeRaw       -- Raw content JSON
```

**Problem**: Only `ModeTemplate` is ever set. The `argJson`/`argRaw` command-line flags control behavior directly in `printResult()`, bypassing the `OutputMode` mechanism entirely. The `ModeJson` and `ModeRaw` branches in `renderItem` are unreachable.

**Impact**: Dead code - the `OutputMode` type and its pattern matching could be removed.

### renderItem Unreachable Branches (Renderer.hs:192-204)

```haskell
renderItem cfg item = case rcMode cfg of
  ModeJson -> pure Nothing      -- UNREACHABLE
  ModeRaw -> pure Nothing       -- UNREACHABLE
  ModeTemplate -> ...           -- Always taken
```

These branches exist but can never execute given current call patterns.

## Generated Template Quality Issues

Current generation produces flat variable dumps:

```mustache
{{! arbor.tree_list }}
{{tree_id}} {{tree_ids}} {{new_count}} {{owner_id}} ...
```

### Issues

1. **No formatting or structure** - All fields on single line
2. **No iteration blocks** - Arrays not handled with `{{#items}}...{{/items}}`
3. **No conditional sections** - Optional fields not wrapped in `{{#field}}...{{/field}}`
4. **Fallback often better** - `prettyValue` produces more readable output

### Template Quality Statistics

- 23 celestial templates contain only `{{.}}` (simple pass-through)
- Many templates are effectively placeholders

## ✅ Resolved: IR-Driven Template Generation (Implemented)

The template system now uses IR for generation and includes runtime data transformation:

### Key Changes

1. **Variant-Based Naming**: Templates now use `{namespace}/{variant}.mustache` which matches the runtime `content_type` (e.g., `health/status.mustache` for `content_type: "health.status"`)

2. **Per-Variant Templates**: Union return types generate one template per variant, not one per method

3. **Discriminated Union Wrapping** (`Renderer.hs`):
   ```haskell
   wrapDiscriminatedUnion :: Value -> Value
   wrapDiscriminatedUnion (Object obj) =
     case KM.lookup "type" obj of
       Just (String variant) ->
         Object $ KM.singleton (K.fromText variant) (Object obj)
       _ -> Object obj
   ```
   This transforms `{"type": "echo", "count": 1}` to `{"echo": {"type": "echo", "count": 1}}` so mustache sections `{{#echo}}...{{/echo}}` match correctly.

4. **CLI.Template Module** (`src/Synapse/CLI/Template.hs`):
   - `generateTemplates :: IR -> MethodDef -> [GeneratedTemplate]`
   - `generateVariantTemplate :: IR -> MethodDef -> VariantDef -> GeneratedTemplate`
   - `generateVariantBody :: IR -> VariantDef -> Text`

### Remaining Limitations

| Limitation | Description |
|------------|-------------|
| **Dead code** | `OutputMode` enum still unused (could be removed) |
| **anyOf handling** | `anyOf` unions not yet supported in IR Builder |

## Relationship to IR-Based CLI

The CLI now uses IR (Intermediate Representation) for:

- **Help rendering** (`CLI.Help`)
- **Parameter parsing** (`CLI.Parse`)
- **Support checking** (`CLI.Support`)

Templates should also use IR for consistency:

- IR has structured return types (`TypeDef`, `TypeKind`)
- Could generate better templates from type information
- Variant-aware rendering for tagged unions (sum types)

## Proposed Improvements

### 1. ~~Remove Dead Code~~ (TODO)

Eliminate `OutputMode` type and simplify `renderItem` to always use template mode. JSON/raw output handled separately in `printResult`.

### 2. ✅ IR-Driven Template Generation (DONE)

Templates are now generated from IR via `CLI.Template`:

```haskell
generateTemplates :: IR -> MethodDef -> [GeneratedTemplate]
typeRefToMustache :: IR -> Int -> TypeRef -> Text
```

### 3. ✅ Structured Generation (DONE)

Templates now generate multi-line output with proper sections and variant wrapping.

### 4. ✅ Tagged Union Support (DONE)

Variants are rendered via mustache sections after `wrapDiscriminatedUnion` transforms the data:

```mustache
{{! cone.content }}
{{#content}}{{text}}{{/content}}
```

## File Reference Summary

| File | Path | Purpose |
|------|------|---------|
| Renderer.hs | `src/Synapse/Renderer.hs` | Template cache, resolution, rendering |
| TemplateGen.hs | `src/Synapse/Algebra/TemplateGen.hs` | Schema → Mustache generation |
| Main.hs | `app/Main.hs` | CLI entry point, `printResult` dispatch |

## Related Documents

- `16679052837278386687_ir-cli-implementation.md` - IR-based CLI architecture
- `16679155106803598591_ir-based-cli.md` - IR design for CLI
- `16679164194740300543_unified-cli-tree.md` - CLI command tree structure
