Add an AGENTS.md file to project
This commit is contained in:
parent
dfe05b2456
commit
8728e0062a
131
AGENTS.md
Normal file
131
AGENTS.md
Normal file
@ -0,0 +1,131 @@
|
|||||||
|
# AGENTS.md
|
||||||
|
|
||||||
|
This file provides guidance to coding agents working in this repository.
|
||||||
|
|
||||||
|
## Mission
|
||||||
|
|
||||||
|
`integrations` is an early-stage repository for integration work across Rust, Python, and Haskell-related research notes.
|
||||||
|
|
||||||
|
At the time of writing, the repository is still close to a template scaffold. Some names and files still reflect that origin. Treat the current codebase as incomplete infrastructure unless the user says otherwise.
|
||||||
|
|
||||||
|
Priorities, in order:
|
||||||
|
|
||||||
|
1. Keep changes aligned with the actual repository state.
|
||||||
|
2. Prefer small, targeted edits over broad cleanup.
|
||||||
|
3. Preserve a clear separation between code, tooling, and research notes.
|
||||||
|
4. Keep documentation factual and easy to scan.
|
||||||
|
|
||||||
|
## Current Repository State
|
||||||
|
|
||||||
|
- The Rust code lives under `rust/` rather than the usual `src/` layout.
|
||||||
|
- The repository still contains some scaffold residue, but the main Rust crate naming should match `integrations`.
|
||||||
|
- `README.md` is minimal and does not define a stable product scope yet.
|
||||||
|
- `pyproject.toml` sets up a Python environment with `maturin[zig]` and `numpy`.
|
||||||
|
- `haskell/notes/` contains project review notes.
|
||||||
|
- `tmp/` contains temporary or inspected repositories and should not be treated as product code unless the user asks for that specifically.
|
||||||
|
|
||||||
|
Do not assume the repository is complete or internally consistent.
|
||||||
|
|
||||||
|
## Directory Guide
|
||||||
|
|
||||||
|
- `rust/`
|
||||||
|
- Main Rust sources.
|
||||||
|
- Current files include CLI and logging scaffolding.
|
||||||
|
- Keep changes here minimal and consistent with the existing file layout unless the user asks for restructuring.
|
||||||
|
|
||||||
|
- `haskell/notes/`
|
||||||
|
- Notes and reviews of Haskell-related projects or integration experiments.
|
||||||
|
- Use `haskell/notes/_template.md` as the default format.
|
||||||
|
- Write in a factual review style.
|
||||||
|
|
||||||
|
- `tmp/`
|
||||||
|
- Scratch space, cloned repos, and inspection targets.
|
||||||
|
- Do not treat files here as part of the maintained codebase unless the task explicitly targets them.
|
||||||
|
|
||||||
|
- `Makefile`
|
||||||
|
- Project convenience commands.
|
||||||
|
- Some targets may still reflect template assumptions.
|
||||||
|
|
||||||
|
- `.pre-commit-config.yaml`
|
||||||
|
- Hook configuration for formatting, linting, and tests.
|
||||||
|
|
||||||
|
## Core Rules
|
||||||
|
|
||||||
|
- Use English for code, comments, docs, tests, and notes.
|
||||||
|
- Keep edits scoped to the user request.
|
||||||
|
- Do not perform broad template cleanup unless the user asks for it.
|
||||||
|
- Do not remove template residue just because it is present.
|
||||||
|
- When you find template leftovers, note them if relevant, but do not expand scope without approval.
|
||||||
|
- Add comments only when they clarify non-obvious behavior.
|
||||||
|
- Keep documentation factual. Do not use poetic wording or decorative language.
|
||||||
|
|
||||||
|
## Rust Conventions
|
||||||
|
|
||||||
|
- Target the toolchain in `rust-toolchain.toml`.
|
||||||
|
- Follow existing lint expectations from the `Makefile`.
|
||||||
|
- Avoid `unwrap()` and `expect()` in production code unless there is a clear justification.
|
||||||
|
- Prefer explicit error handling with `Result`.
|
||||||
|
- Prefer simple APIs and small modules over speculative abstraction.
|
||||||
|
- Use `tracing` consistently where logging is already part of the flow.
|
||||||
|
|
||||||
|
## Python Conventions
|
||||||
|
|
||||||
|
- Treat `pyproject.toml` as environment support for the repository, not as proof that a Python application exists.
|
||||||
|
- Do not add Python dependencies unless the task requires them.
|
||||||
|
- Keep Python-related changes minimal and tied to integration needs.
|
||||||
|
|
||||||
|
## Notes Conventions
|
||||||
|
|
||||||
|
Applies to files under `haskell/notes/`:
|
||||||
|
|
||||||
|
- Use Title Case for headings.
|
||||||
|
- Write like a reviewer.
|
||||||
|
- Keep the tone factual and direct.
|
||||||
|
- Avoid colorful adjectives and adverbs.
|
||||||
|
- Prefer short paragraphs and short lists.
|
||||||
|
- State strengths, weaknesses, and status directly.
|
||||||
|
- If something is incomplete, fragile, or early, say so plainly.
|
||||||
|
|
||||||
|
## Validation
|
||||||
|
|
||||||
|
Validate as narrowly as possible.
|
||||||
|
|
||||||
|
For Rust changes, prefer the smallest relevant check first. Examples:
|
||||||
|
|
||||||
|
1. `cargo test` for the affected crate or module
|
||||||
|
2. `cargo clippy` if the Rust workspace is in a runnable state
|
||||||
|
3. `cargo fmt --check` or `cargo fmt`
|
||||||
|
|
||||||
|
If the repository is missing required manifests or is otherwise not runnable, do not fix unrelated scaffolding unless the user asks. Report the limitation clearly.
|
||||||
|
|
||||||
|
For notes-only changes, no build validation is required.
|
||||||
|
|
||||||
|
## Change Design Checklist
|
||||||
|
|
||||||
|
Before editing:
|
||||||
|
|
||||||
|
1. Confirm whether the target is maintained code, tooling, notes, or scratch material.
|
||||||
|
2. Check whether the repository state supports validation.
|
||||||
|
3. Keep the change limited to the stated task.
|
||||||
|
|
||||||
|
Before finishing:
|
||||||
|
|
||||||
|
1. Verify the requested files were updated.
|
||||||
|
2. Run targeted validation when it applies.
|
||||||
|
3. Call out any template residue or missing infrastructure that affects confidence.
|
||||||
|
|
||||||
|
## Review Guidance
|
||||||
|
|
||||||
|
When reviewing or summarizing work in this repository:
|
||||||
|
|
||||||
|
- Focus on correctness, maintainability, and scope control.
|
||||||
|
- Distinguish between template residue and task-specific issues.
|
||||||
|
- Do not recommend broad cleanup unless it is required.
|
||||||
|
- Keep findings concise and factual.
|
||||||
|
|
||||||
|
## Practical Notes For Agents
|
||||||
|
|
||||||
|
- The current repository is not a finished product. Avoid assumptions about intended architecture.
|
||||||
|
- `tmp/` is usually for inspection work, not implementation work.
|
||||||
|
- `haskell/notes/` is part of the maintained repo and should stay consistent in tone and format.
|
||||||
|
- If the user asks for project-level cleanup, identify template leftovers first and then propose a scoped plan.
|
||||||
18
Cargo.toml
Normal file
18
Cargo.toml
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
[package]
|
||||||
|
name = "integrations"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
license = "MIT OR Apache-2.0"
|
||||||
|
publish = false
|
||||||
|
|
||||||
|
[lib]
|
||||||
|
path = "rust/lib.rs"
|
||||||
|
|
||||||
|
[[bin]]
|
||||||
|
name = "integrations"
|
||||||
|
path = "rust/main.rs"
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
ctor = "0.2"
|
||||||
|
tracing = "0.1"
|
||||||
|
tracing-subscriber = "0.3"
|
||||||
12
Makefile
12
Makefile
@ -1,14 +1,6 @@
|
|||||||
# Load environment variables from .env file
|
|
||||||
ifneq (,$(wildcard ./.env))
|
|
||||||
include .env
|
|
||||||
export $(shell sed 's/=.*//' .env)
|
|
||||||
else
|
|
||||||
$(warning .env file not found. Environment variables not loaded.)
|
|
||||||
endif
|
|
||||||
|
|
||||||
# Variables
|
# Variables
|
||||||
PROJ_REPO = github.com/habedi/template-rust-project
|
PROJ_REPO = code.obsidian.systems/habedi-work/integrations
|
||||||
BINARY_NAME := $(or $(PROJ_BINARY), $(notdir $(PROJ_REPO)))
|
BINARY_NAME := $(or $(PROJ_BINARY), integrations)
|
||||||
BINARY := target/release/$(BINARY_NAME)
|
BINARY := target/release/$(BINARY_NAME)
|
||||||
PATH := /snap/bin:$(PATH)
|
PATH := /snap/bin:$(PATH)
|
||||||
DEBUG_PROJ := 0
|
DEBUG_PROJ := 0
|
||||||
|
|||||||
@ -12,7 +12,7 @@ The repo is testing a specific pipeline:
|
|||||||
|
|
||||||
Rust exports a C ABI -> `cbindgen` emits a header -> `hs-bindgen` produces Haskell bindings -> hand-written Haskell wrappers clean up the API.
|
Rust exports a C ABI -> `cbindgen` emits a header -> `hs-bindgen` produces Haskell bindings -> hand-written Haskell wrappers clean up the API.
|
||||||
|
|
||||||
It succeeds as a demo. It does not read as production-ready infrastructure.
|
The repo demonstrates the pipeline. It is not production-ready infrastructure.
|
||||||
|
|
||||||
## What It Contains
|
## What It Contains
|
||||||
|
|
||||||
@ -25,50 +25,49 @@ It succeeds as a demo. It does not read as production-ready infrastructure.
|
|||||||
|
|
||||||
## Review
|
## Review
|
||||||
|
|
||||||
The project makes the intended architecture clear. Separating raw bindings from the wrapper layer is the right call, and the examples are broad enough
|
The architecture is clear. The split between raw bindings and wrapper code is appropriate. The examples cover more than trivial FFI cases.
|
||||||
to be useful. This is more than a toy "add two numbers" demo.
|
|
||||||
|
|
||||||
That said, the repo still looks early. The build is custom, the dependency stack is pinned to git revisions, and the Rust build script contains a
|
The project is still early. The build is custom, the dependencies are pinned to git revisions, and the Rust build script contains a workaround for
|
||||||
workaround for upstream tooling issues. That combination is acceptable in an experiment, but it is a weak base for a maintained integration layer.
|
upstream tooling issues. That is acceptable for an experiment, but it is a weak base for a maintained integration layer.
|
||||||
|
|
||||||
The biggest limitation is that code generation does not remove the hard part. The Haskell side still needs manual wrapper code to turn raw bindings
|
The main limitation is that code generation does not remove the manual work. The Haskell side still needs wrapper code to produce a usable API.
|
||||||
into something ergonomic. The repo proves that the pipeline works, but it also shows that the pipeline is not yet cheap.
|
The repo shows that the pipeline works. It also shows that the workflow still has overhead.
|
||||||
|
|
||||||
## Pros
|
## Pros
|
||||||
|
|
||||||
- The architecture is clean enough to follow.
|
- The architecture is easy to inspect.
|
||||||
- The examples cover realistic FFI shapes, not just trivial functions.
|
- The examples cover multiple FFI cases.
|
||||||
- The split between generated and hand-written code is sensible.
|
- The split between generated and hand-written code is reasonable.
|
||||||
- The repo is small enough to serve as a reference implementation.
|
- The repo is small enough to review quickly.
|
||||||
|
|
||||||
## Cons
|
## Cons
|
||||||
|
|
||||||
- The build flow is manual and brittle.
|
- The build flow is manual.
|
||||||
- The setup depends on alpha-stage or pinned upstream tooling.
|
- The setup depends on alpha-stage or pinned upstream tooling.
|
||||||
- The local header patch is a red flag for maintainability.
|
- The local header patch adds maintenance risk.
|
||||||
- The wrapper layer still carries noticeable manual boilerplate.
|
- The wrapper layer still requires manual boilerplate.
|
||||||
- There is no obvious sign of tests, CI, or a long-term stability plan.
|
- There is no visible test, CI, or long-term maintenance plan.
|
||||||
|
|
||||||
## Status
|
## Status
|
||||||
|
|
||||||
Current status: working prototype.
|
Current status: working prototype.
|
||||||
|
|
||||||
It appears far enough along to prove the interop path and demonstrate the tooling choices. It does not appear far enough along to support repeated
|
The repo is far enough along to prove the interop path and demonstrate the tooling choices. It is not far enough along to support repeated reuse
|
||||||
reuse without more work on build integration, test coverage, and dependency stability.
|
without more work on build integration, test coverage, and dependency stability.
|
||||||
|
|
||||||
In reviewer terms: promising experiment, useful reference, not ready to trust as infrastructure.
|
Reviewer verdict: useful experiment, not ready to treat as infrastructure.
|
||||||
|
|
||||||
## Ecosystem Maturity
|
## Ecosystem Maturity
|
||||||
|
|
||||||
Rust/Haskell interop is uneven.
|
Rust/Haskell interop is uneven.
|
||||||
|
|
||||||
The low-level foundation is mature enough. Haskell has had a solid FFI story for years, and Rust is comfortable exporting or importing a C ABI.
|
The low-level foundation is mature enough. Haskell has had an FFI story for years, and Rust can export or import a C ABI.
|
||||||
If the boundary is narrow and C-like, the approach is viable.
|
If the boundary is narrow and C-like, the approach is viable.
|
||||||
|
|
||||||
The weak part is the tooling layer. Header generation on the Rust side is serviceable. Binding generation on the Haskell side is improving, but it
|
The weak part is the tooling layer. Header generation on the Rust side is usable. Binding generation on the Haskell side is improving, but it
|
||||||
still looks early. The Garnet repo reflects that gap exactly: the ABI path works, but the workflow still needs custom glue and hand-written cleanup.
|
still looks early. The Garnet repo reflects that gap exactly: the ABI path works, but the workflow still needs custom glue and hand-written cleanup.
|
||||||
|
|
||||||
Reviewer verdict: mature enough for disciplined teams, not mature enough to feel easy.
|
Reviewer verdict: usable for a disciplined team, not easy.
|
||||||
|
|
||||||
## Calling Direction
|
## Calling Direction
|
||||||
|
|
||||||
@ -79,14 +78,14 @@ This is the easier direction.
|
|||||||
Rust can expose a conventional C ABI, and Haskell can consume it through its normal FFI mechanisms. That keeps the ownership model and runtime story
|
Rust can expose a conventional C ABI, and Haskell can consume it through its normal FFI mechanisms. That keeps the ownership model and runtime story
|
||||||
relatively simple, at least compared with the reverse direction.
|
relatively simple, at least compared with the reverse direction.
|
||||||
|
|
||||||
This is the path Garnet takes, and it is the right first choice.
|
This is the path Garnet takes. It is the better default.
|
||||||
|
|
||||||
### Calling Haskell From Rust
|
### Calling Haskell From Rust
|
||||||
|
|
||||||
This is the harder direction.
|
This is the harder direction.
|
||||||
|
|
||||||
Once Rust starts calling into Haskell, the GHC runtime becomes part of the design. That raises the complexity around runtime initialization,
|
Once Rust starts calling into Haskell, the GHC runtime becomes part of the design. That raises the complexity around runtime initialization,
|
||||||
threading, callbacks, shutdown, and operational correctness. It is possible, but it is a sharper tool and a worse default.
|
threading, callbacks, shutdown, and operational correctness. It is possible, but it is a worse default.
|
||||||
|
|
||||||
Reviewer verdict: call Rust from Haskell when possible; only call Haskell from Rust when there is a strong reason.
|
Reviewer verdict: call Rust from Haskell when possible; only call Haskell from Rust when there is a strong reason.
|
||||||
|
|
||||||
@ -100,14 +99,14 @@ Current best default:
|
|||||||
- keep Haskell bindings thin
|
- keep Haskell bindings thin
|
||||||
- write the final Haskell API by hand
|
- write the final Haskell API by hand
|
||||||
|
|
||||||
That is not glamorous, but it is the most credible path today.
|
That is the most credible path today.
|
||||||
|
|
||||||
For teams that want the lowest risk, hand-written Haskell FFI bindings are still easier to trust than a large generated surface. For teams exploring
|
For teams that want the lowest risk, hand-written Haskell FFI bindings are still easier to trust than a large generated surface. For teams exploring
|
||||||
automation, `hs-bindgen` is interesting but still reads as early-stage technology.
|
automation, `hs-bindgen` is worth watching but is still early-stage technology.
|
||||||
|
|
||||||
## Practical Read On Garnet
|
## Practical Read On Garnet
|
||||||
|
|
||||||
Garnet is valuable because it shows both sides of the story.
|
Garnet is useful because it shows both sides of the story.
|
||||||
|
|
||||||
It shows that the basic interop path works. It also shows that the surrounding tooling is not yet smooth enough to disappear into the background.
|
It shows that the basic interop path works. It also shows that the surrounding tooling is not yet smooth enough to disappear into the background.
|
||||||
That makes it a good experiment and a fair warning.
|
It is a useful experiment and a warning about the current workflow cost.
|
||||||
|
|||||||
@ -28,7 +28,7 @@ Say what still looks early, brittle, overcomplicated, missing, or high-risk.
|
|||||||
|
|
||||||
Call out the main constraint directly: <build glue / unstable deps / missing tests / wrapper burden / runtime complexity / unclear ownership / etc.>
|
Call out the main constraint directly: <build glue / unstable deps / missing tests / wrapper burden / runtime complexity / unclear ownership / etc.>
|
||||||
|
|
||||||
Keep this section short and judgmental in the useful sense. Write like a reviewer, not a tour guide.
|
Keep this section short. Write like a reviewer, not a tour guide.
|
||||||
|
|
||||||
## Pros
|
## Pros
|
||||||
|
|
||||||
@ -75,3 +75,6 @@ Add only if they help:
|
|||||||
- Prefer verdicts over summaries when the evidence is already clear.
|
- Prefer verdicts over summaries when the evidence is already clear.
|
||||||
- If something is fragile, say it is fragile.
|
- If something is fragile, say it is fragile.
|
||||||
- If something is promising but early, say that plainly.
|
- If something is promising but early, say that plainly.
|
||||||
|
- Do not use poetic wording.
|
||||||
|
- Avoid colorful adjectives and adverbs.
|
||||||
|
- Prefer factual wording over rhetorical wording.
|
||||||
|
|||||||
@ -3,8 +3,6 @@ use tracing::error;
|
|||||||
|
|
||||||
pub fn run(args: impl IntoIterator<Item = OsString>) -> Result<(), i32> {
|
pub fn run(args: impl IntoIterator<Item = OsString>) -> Result<(), i32> {
|
||||||
let _args: Vec<OsString> = args.into_iter().collect();
|
let _args: Vec<OsString> = args.into_iter().collect();
|
||||||
// Your implementation here
|
|
||||||
// Expecting at least 2 arguments
|
|
||||||
if _args.len() < 2 {
|
if _args.len() < 2 {
|
||||||
error!("Expecting at least 2 arguments");
|
error!("Expecting at least 2 arguments");
|
||||||
return Err(1);
|
return Err(1);
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
use template_rust_project::cli::run;
|
use integrations::cli::run;
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
if let Err(code) = run(std::env::args_os()) {
|
if let Err(code) = run(std::env::args_os()) {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user