
AutoTally has one central design fact: **everything that touches Tally is .NET, and
everything agent-facing is TypeScript.** The two halves meet at a single HTTP/JSON
contract — the Bridge REST API.

```text
TS  (agent-facing):  mcp-server / cli / relay   ──HTTP/JSON──▶  Bridge REST API
.NET (Tally-facing): Bridge ─▶ Core ─▶ TallyConnector  ──XML──▶  Tally (:9000)
```

## The contract is the source of truth

`openapi.yaml` is shared by both stacks. When an endpoint or DTO changes, all three
change in lockstep: the OpenAPI spec, the .NET side, and the hand-maintained
TypeScript types that mirror it.

## Why split it this way

- The .NET side calls the upstream `TallyConnector` library **in-process**, so it can
  speak Tally's XML dialect without reimplementing it.
- The TypeScript side owns everything an agent sees — the MCP tools, the CLI, and the
  relay — where the ecosystem is richest.

## Layers

| Layer | Stack | Responsibility |
| --- | --- | --- |
| MCP server | TypeScript | Exposes Tally operations as typed agent tools |
| CLI | TypeScript | Human + scripting access to the same contract |
| Bridge REST API | .NET | The one HTTP/JSON contract |
| Core | .NET | Maps DTOs to connector calls |
| TallyConnector | .NET | The Tally XML/HTTP protocol layer |

Read [Write safety](/docs/concepts/write-safety) for the guardrails that live along
the write path.
