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
|
||||
PROJ_REPO = github.com/habedi/template-rust-project
|
||||
BINARY_NAME := $(or $(PROJ_BINARY), $(notdir $(PROJ_REPO)))
|
||||
PROJ_REPO = code.obsidian.systems/habedi-work/integrations
|
||||
BINARY_NAME := $(or $(PROJ_BINARY), integrations)
|
||||
BINARY := target/release/$(BINARY_NAME)
|
||||
PATH := /snap/bin:$(PATH)
|
||||
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.
|
||||
|
||||
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
|
||||
|
||||
@ -25,50 +25,49 @@ It succeeds as a demo. It does not read as production-ready infrastructure.
|
||||
|
||||
## 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
|
||||
to be useful. This is more than a toy "add two numbers" demo.
|
||||
The architecture is clear. The split between raw bindings and wrapper code is appropriate. The examples cover more than trivial FFI cases.
|
||||
|
||||
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
|
||||
workaround for upstream tooling issues. That combination is acceptable in an experiment, but it is a weak base for a maintained integration layer.
|
||||
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
|
||||
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
|
||||
into something ergonomic. The repo proves that the pipeline works, but it also shows that the pipeline is not yet cheap.
|
||||
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.
|
||||
The repo shows that the pipeline works. It also shows that the workflow still has overhead.
|
||||
|
||||
## Pros
|
||||
|
||||
- The architecture is clean enough to follow.
|
||||
- The examples cover realistic FFI shapes, not just trivial functions.
|
||||
- The split between generated and hand-written code is sensible.
|
||||
- The repo is small enough to serve as a reference implementation.
|
||||
- The architecture is easy to inspect.
|
||||
- The examples cover multiple FFI cases.
|
||||
- The split between generated and hand-written code is reasonable.
|
||||
- The repo is small enough to review quickly.
|
||||
|
||||
## Cons
|
||||
|
||||
- The build flow is manual and brittle.
|
||||
- The build flow is manual.
|
||||
- The setup depends on alpha-stage or pinned upstream tooling.
|
||||
- The local header patch is a red flag for maintainability.
|
||||
- The wrapper layer still carries noticeable manual boilerplate.
|
||||
- There is no obvious sign of tests, CI, or a long-term stability plan.
|
||||
- The local header patch adds maintenance risk.
|
||||
- The wrapper layer still requires manual boilerplate.
|
||||
- There is no visible test, CI, or long-term maintenance plan.
|
||||
|
||||
## Status
|
||||
|
||||
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
|
||||
reuse without more work on build integration, test coverage, and dependency stability.
|
||||
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
|
||||
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
|
||||
|
||||
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.
|
||||
|
||||
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.
|
||||
|
||||
Reviewer verdict: mature enough for disciplined teams, not mature enough to feel easy.
|
||||
Reviewer verdict: usable for a disciplined team, not easy.
|
||||
|
||||
## 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
|
||||
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
|
||||
|
||||
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,
|
||||
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.
|
||||
|
||||
@ -100,14 +99,14 @@ Current best default:
|
||||
- keep Haskell bindings thin
|
||||
- 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
|
||||
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
|
||||
|
||||
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.
|
||||
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.>
|
||||
|
||||
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
|
||||
|
||||
@ -75,3 +75,6 @@ Add only if they help:
|
||||
- Prefer verdicts over summaries when the evidence is already clear.
|
||||
- If something is fragile, say it is fragile.
|
||||
- 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> {
|
||||
let _args: Vec<OsString> = args.into_iter().collect();
|
||||
// Your implementation here
|
||||
// Expecting at least 2 arguments
|
||||
if _args.len() < 2 {
|
||||
error!("Expecting at least 2 arguments");
|
||||
return Err(1);
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
use template_rust_project::cli::run;
|
||||
use integrations::cli::run;
|
||||
|
||||
fn main() {
|
||||
if let Err(code) = run(std::env::args_os()) {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user