Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
80 changes: 9 additions & 71 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@

## Project Overview

ArchML is a text-based DSL for defining software architecture alongside code. It covers functional, behavioral, and deployment architecture domains with consistency checking, navigable web views, and native Sphinx integration. Architecture files use the `.archml` extension.
ArchML is a text-based DSL for defining software architecture alongside code.
It covers functional, behavioral, and deployment architecture domains with consistency checking, navigable web views, and native Sphinx integration. Architecture files use the `.archml` extension.

The project is in early development. The DSL syntax for functional architecture is specified in `docs/LANGUAGE_SYNTAX.md`. The overall vision and landscape analysis are in `docs/PROJECT_SCOPE.md`.

## Tech Stack

Expand All @@ -13,42 +13,11 @@ The project is in early development. The DSL syntax for functional architecture
- **Linter/formatter**: ruff
- **Type checker**: ty
- **Testing**: pytest
- **Documentation**: Sphinx (ArchML views will embed natively via a Sphinx extension)
- **Documentation**: Sphinx
- **Distribution**: PyPI

## Project Structure (Target)

```
archml/
├── CLAUDE.md
├── README.md
├── LICENSE
├── pyproject.toml
├── docs/
│ ├── PROJECT_SCOPE.md
│ ├── LANGUAGE_SYNTAX.md
│ └── sphinx/ # Sphinx documentation source
├── src/
│ └── archml/
│ ├── __init__.py
│ ├── parser/ # Lexer and parser for .archml files
│ ├── model/ # Semantic model (systems, components, interfaces, etc.)
│ ├── validation/ # Consistency checks (dangling refs, unused interfaces)
│ ├── views/ # View generation and rendering
│ ├── sphinx_ext/ # Sphinx extension for embedding architecture views
│ ├── lsp/ # Language server (LSP) for VS Code integration
│ ├── webui/ # Dash-based web UI for interactive architecture viewing
│ └── cli/ # Command-line interface
└── tests/ # All tests (mirrors src/ structure)
├── parser/
├── model/
├── validation/
├── views/
├── sphinx_ext/
├── lsp/
├── webui/
└── cli/
```
## Project Structure (Target)

## Common Commands

Expand All @@ -59,9 +28,6 @@ uv sync
# Run all tests
uv run pytest

# Run tests with coverage
uv run pytest --cov=archml

# Run a specific test file or test
uv run pytest tests/parser/test_lexer.py
uv run pytest -k "test_parse_component"
Expand All @@ -72,12 +38,6 @@ uv run ruff format src/ tests/

# Type check
uv run ty check src/

# Build the package
uv build

# Build Sphinx docs
uv run sphinx-build docs/sphinx docs/sphinx/_build
```

## Development Methodology
Expand All @@ -90,37 +50,15 @@ Every new feature requires thorough testing before it is considered complete. Th
4. Ensure all tests pass, ruff reports no issues, and ty finds no type errors using `uv run tools/ci.py`.
5. Commit with a clear message describing the change.

Tests are not optional. A feature without tests is not done.

## ArchML Language Quick Reference
Tests are not optional.
A feature without tests is not done.

The DSL defines architecture through these core constructs:

- **`system`** — groups components or sub-systems
- **`component`** — module with `requires` and `provides` interface declarations; supports nesting
- **`user`** — human actor (role or persona) that interacts with the system; a leaf node
- **`interface`** — typed contract between elements; supports versioning (`@v1`, `@v2`)
- **`type`** — reusable data structure used within interfaces
- **`enum`** — constrained set of named values
- **`connect`** — data-flow edge linking a required interface to a provided interface (`connect A -> B by Interface`)
- **`external`** — marks a system, component, or user as outside the development boundary
- **`import` / `use`** — multi-file composition; `use` always includes the entity type (e.g., `use component X`)
- **`tags`** — arbitrary labels for filtering and view generation
- **`field`** — typed data element with optional `description` and `schema` annotations

Primitive types: `String`, `Int`, `Float`, `Decimal`, `Bool`, `Bytes`, `Timestamp`, `Datetime`
Container types: `List<T>`, `Map<K, V>`, `Optional<T>`
Filesystem types: `File` (with `filetype`, `schema`), `Directory` (with `schema`)
## ArchML Language Quick Reference

Full syntax specification: `docs/LANGUAGE_SYNTAX.md`

## Architecture and Design Decisions

- The parser produces an AST which is then lowered into a semantic model. Validation runs on the semantic model, not the AST.
- Views are not part of the architecture language. They will be defined in a separate view DSL that references model entities.
- The Sphinx extension reads `.archml` files directly and renders views inline — it is not an export pipeline.
- The CLI is the primary user entry point for parsing, validating, and generating views outside of Sphinx.
- A Language Server Protocol (LSP) implementation provides IDE support (diagnostics, completion, go-to-definition) for `.archml` files, with a VS Code extension as the primary client.

## Coding Conventions

Expand All @@ -129,6 +67,7 @@ Full syntax specification: `docs/LANGUAGE_SYNTAX.md`
- Prefer dataclasses or attrs for model types.
- Keep modules focused: one responsibility per module.
- The test directory structure mirrors the source structure. Every module in `src/archml/<package>/` has a corresponding directory in `tests/<package>/`. Test files are prefixed with `test_`: `src/archml/parser/lexer.py` -> `tests/parser/test_lexer.py`.
- Use proper docstrings for public functions.
- Every Python file follows this layout:

```python
Expand All @@ -142,7 +81,6 @@ import ...
# ###############

def public_function() -> None:
"""Docstring describing the function."""
...

# ################
Expand All @@ -153,4 +91,4 @@ def _private_helper() -> None:
...
```

The copyright header and imports come first. Public interface (classes, functions, constants) is separated from private implementation by section comments. All private members are prefixed with an underscore.
The copyright header and imports come first. Public interface (classes, functions, constants) is separated from private implementation by section comments. All private members are prefixed with an underscore.
69 changes: 45 additions & 24 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -87,10 +87,26 @@ system ECommerce {
title = "Order Service"
description = "Accepts, validates, and processes customer orders."

requires OrderRequest
requires PaymentRequest
requires InventoryCheck
provides OrderConfirmation
// Internal pipeline: Validator feeds into Processor
component Validator {
requires OrderRequest as input
provides ValidationResult as output
}

component Processor {
requires ValidationResult as input
requires PaymentRequest
requires InventoryCheck
provides OrderConfirmation
}

connect Validator.output -> Processor.input

// Promote inner ports to the OrderService boundary
expose Validator.input // requires OrderRequest
expose Processor.PaymentRequest // requires PaymentRequest
expose Processor.InventoryCheck // requires InventoryCheck
expose Processor.OrderConfirmation // provides OrderConfirmation
}

component PaymentGateway {
Expand All @@ -104,14 +120,15 @@ system ECommerce {
component InventoryManager {
title = "Inventory Manager"

requires InventoryCheck
requires InventoryCheck as requests [1..*] // accepts requests from multiple sources
provides InventoryStatus
}

connect Customer -> OrderService by OrderRequest
connect OrderService -> Customer by OrderConfirmation
connect OrderService -> PaymentGateway by PaymentRequest
connect OrderService -> InventoryManager by InventoryCheck {
// Short form: interface is unambiguous on both sides
connect Customer -> OrderService by OrderRequest
connect OrderService -> Customer by OrderConfirmation
connect OrderService -> PaymentGateway by PaymentRequest
connect OrderService -> InventoryManager by InventoryCheck {
protocol = "HTTP"
}
connect PaymentGateway -> StripeAPI by PaymentRequest {
Expand All @@ -125,21 +142,25 @@ Large architectures split naturally across files. A `from ... import` statement

## Language at a Glance

| Keyword | Purpose |
| ----------------------- | --------------------------------------------------------------------- |
| `system` | Group of components or sub-systems with a shared goal |
| `component` | Module with a clear responsibility; may nest sub-components |
| `user` | Human actor (role or persona) that interacts with the system |
| `interface` | Named contract of typed data fields; supports `@v1`, `@v2` versioning |
| `type` | Reusable data structure (used within interfaces) |
| `enum` | Constrained set of named values |
| `field` | Named, typed data element with optional `description` and `schema` |
| `requires` / `provides` | Declare consumed and exposed interfaces on a component or user |
| `connect A -> B by I` | Data-flow edge linking a required interface to a provided one |
| `external` | Marks a system, component, or user as outside the development boundary |
| `from … import` | Bring specific definitions from another file into scope |
| `use component X` | Place an imported entity inside a system |
| `tags` | Arbitrary labels for filtering and view generation |
| Keyword | Purpose |
| ---------------------------- | --------------------------------------------------------------------------------- |
| `system` | Group of components or sub-systems with a shared goal |
| `component` | Module with a clear responsibility; may nest sub-components |
| `user` | Human actor (role or persona) that interacts with the system |
| `interface` | Named contract of typed data fields; supports `@v1`, `@v2` versioning |
| `type` | Reusable data structure (used within interfaces) |
| `enum` | Constrained set of named values |
| `field` | Named, typed data element with optional `description` and `schema` |
| `requires` / `provides` | Declare consumed and exposed interface ports on a component or user |
| `requires X as name` | Named port — required when the same interface appears more than once |
| `requires X as name [1..*]` | Multi-port with cardinality — for fan-in patterns; `[N]`, `[*]`, `[M..N]` also valid |
| `expose Sub.port` | Promote a nested component's port to the enclosing component's boundary |
| `connect A -> B by I` | Short form: wire interface I between A and B (when I is unambiguous on both sides) |
| `connect A.p -> B.p` | Long form: wire named ports directly (no `by` needed) |
| `external` | Marks a system, component, or user as outside the development boundary |
| `from … import` | Bring specific definitions from another file into scope |
| `use component X` | Place an imported entity inside a system |
| `tags` | Arbitrary labels for filtering and view generation |

Primitive types: `String`, `Int`, `Float`, `Decimal`, `Bool`, `Bytes`, `Timestamp`, `Datetime`
Container types: `List<T>`, `Map<K, V>`, `Optional<T>`
Expand Down
Loading
Loading