Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
aec09cd
docs: design spec for hm.deploy + hm dev local deployments
markovejnovic May 21, 2026
94fce15
docs: implementation plan for hm.deploy + hm.dev DSL
markovejnovic May 21, 2026
ccc621d
feat(deploy): scaffold abstract Deployment dataclass + registry
markovejnovic May 21, 2026
838c4aa
fix(test): conftest resets use canonical public helpers
markovejnovic May 21, 2026
0e05643
feat(dev): add hm.dev.port() sentinel for OS-assigned host ports
markovejnovic May 21, 2026
7dd580c
fix(dev): drop _PortSentinel from __all__; explicit hashability assert
markovejnovic May 21, 2026
66d7385
feat(dev): add LocalDeployment frozen dataclass
markovejnovic May 21, 2026
7aafa31
fix(test): drop unused Step import in test_local_deployment
markovejnovic May 21, 2026
4ae33d6
feat(dev): hm.dev.deploy(...) factory with field validation
markovejnovic May 21, 2026
4b362ce
fix(dev): _factory drops dead isinstance check + minor polish
markovejnovic May 21, 2026
d8a9453
test(dev): rename test_volumes test to reflect actual factory behavior
markovejnovic May 21, 2026
76cea6e
feat(deploy): add hm.Dep[T] marker + extend call_with_deps resolver
markovejnovic May 21, 2026
398f19a
fix(deps): drop unused _DEP_MARKER import
markovejnovic May 21, 2026
3d65b33
fix(deps): Dep error matches Target precedent (TypeError + hm: prefix)
markovejnovic May 21, 2026
06ce0ac
feat(deploy): add @hm.deploy decorator with slug validation + Dep inj…
markovejnovic May 21, 2026
4c1073d
fix(deploy): @hm.deploy uses shared validate_target_signature
markovejnovic May 21, 2026
cf615dc
fix(deploy): duplicate-slug error drops misleading name= hint
markovejnovic May 21, 2026
8ac9e74
feat(deploy): add dep_graph + topo_order over DEPLOYMENTS
markovejnovic May 21, 2026
eb73876
feat(dev): dump_registry_json emits the v0 deployment IR for the CLI
markovejnovic May 21, 2026
3d70d6e
fix(dev): drop dead TYPE_CHECKING import in _registry_dump
markovejnovic May 21, 2026
2691e78
feat(dev): python -m harmont.dev --dump-registry CLI shim
markovejnovic May 21, 2026
05fd295
fix(dev): drop dead `return 2` after parser.error()
markovejnovic May 21, 2026
0238012
docs: document hm.deploy + hm.dev in CLAUDE.md
markovejnovic May 21, 2026
379cece
test(dev): end-to-end canonical db+api+web example
markovejnovic May 21, 2026
0540025
docs(deploy): swap canonical example to python -m http.server
markovejnovic May 22, 2026
158d713
ci: add pytest + ruff + mypy workflow
markovejnovic May 22, 2026
f0ba0fa
docs: remove all plan files
markovejnovic May 22, 2026
18d0993
docs: remove hm-dev-deploy design spec
markovejnovic May 22, 2026
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
40 changes: 40 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
name: CI

on:
pull_request:
push:
branches: [main]

permissions:
contents: read

jobs:
test:
name: pytest + ruff + mypy
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
python-version: ["3.11", "3.12"]
steps:
- uses: actions/checkout@v4

- uses: actions/setup-python@v5
with:
python-version: ${{ matrix.python-version }}
cache: pip

- name: Install harmont + dev extras
run: pip install -e '.[dev]'

- name: ruff check
run: ruff check .

- name: mypy
run: mypy harmont

- name: pytest
run: |
pytest -v \
--deselect tests/test_gradle.py \
--deselect tests/test_haskell.py
53 changes: 53 additions & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -192,6 +192,59 @@ Memoization scope is one `dump_registry_json` render. Two targets
that both depend on `apt_base` share the same `Step`, so the v0 IR
contains one apt-base step with N children — not N copies.

## Deployments — `@hm.deploy` and `hm.dev`

`@hm.deploy` is a driver-agnostic decorator that registers a function
as a long-lived service. The function returns a `Deployment` value
produced by a driver-specific factory; v1 ships only the local Docker
driver via `hm.dev.deploy(...)`. Future cloud drivers (`hm.aws.deploy`,
`hm.fly.deploy`) plug in without touching the top-level decorator.

```python
import harmont as hm

@hm.deploy("hello")
def hello() -> hm.Deployment:
return hm.dev.deploy(
image="python:3.12-alpine",
cmd=["python", "-m", "http.server", "5678"],
port_mapping={5678: hm.dev.port()},
)

@hm.deploy("greeter")
def greeter(hello: hm.Dep[hm.Deployment]) -> hm.Deployment:
return hm.dev.deploy(
image="python:3.12-alpine",
cmd=["python", "-m", "http.server", "5678"],
port_mapping={5678: hm.dev.port()},
env={"HELLO_HOST": hello.name},
)
```

Public surface:

```python
hm.deploy(slug=None, *, name=None) # decorator
hm.Dep[T] # PEP-593 fixture marker
hm.Deployment # abstract dataclass

hm.dev.deploy(*, image=None, from_=None, cmd=None,
port_mapping=None, env=None,
volumes=None, workdir=None) # -> LocalDeployment
hm.dev.port() # OS-assigned host port sentinel
hm.dev.LocalDeployment # concrete subclass
hm.dev.dump_registry_json(*, worktree_root) # -> v0 JSON
```

`hm.dev.port()` is only valid as a value in `port_mapping`. The host
port is assigned by Docker (via `-p :<container_port>`) at `hm dev up`
time; query it from another terminal with `hm dev port-of <slug>
<container_port>`. Ports are fresh on every `hm dev up`.

The Rust CLI (`hm dev up`) shells out to `python -m harmont.dev
--dump-registry` to obtain the registry JSON. Schema is at
`docs/superpowers/specs/2026-05-21-hm-dev-deploy-design.md` § 1.

## Cache keys

`harmont.keygen.resolve_pipeline_keys` ports the algorithm previously
Expand Down
Loading
Loading