Imported from MrBonjour417/ByteTensorCore-demo (
AGENTS.md). Install upstream withnpx skills add MrBonjour417/ByteTensorCore-demo. Copyright stays with the author.
AGENTS.md
Project-specific rules and conventions for AI assistants and contributors.
High-Priority Rules
Do NOT add fields to AcpAgentManager unless every alternative is exhausted
AcpAgentManager (in crates/aionui-ai-agent/src/acp_agent.rs) is already large and carries multiple overlapping state holders (e.g. runtime_snapshot, state, preferred_mode, config). New fields tend to duplicate semantics that AcpRuntimeSnapshot or AcpState already model, which fragments the source of truth and makes resume/new paths diverge.
Before adding a field:
- Can the value live in
AcpRuntimeSnapshot? (runtime/session-scoped state, including user-selected current_mode/current_model/config_selections) - Can it be derived from existing fields (
metadata,config,runtime_snapshot,state)? - Can it be persisted via
acp_session.session_config+preload_persistedinstead of a new in-memory field? - If it must be in-memory and transient, can it be scoped to the call site (local variable, channel, task state) rather than the manager?
Only after exhausting the above — and explicitly documenting why each option is insufficient — add a new field. When doing so, also document its lifecycle (who writes, who reads, when it is invalidated) in a doc comment on the field.
Logging
When planning or changing a critical path or hard-to-observe flow, evaluate whether logging needs to change. In implementation plans for such changes, briefly state whether logs will be added, existing observability is sufficient, or logs are intentionally unnecessary. Do not add logs for simple refactors, test-only changes, UI copy/style changes, or when existing tests, errors, metrics, or logs already provide enough observability.
Add structured logs only when they help verify behavior during development or locate production issues later:
debugfor development-only flow details and state transitionsinfofor low-volume production lifecycle boundaries and important state changeswarnfor malformed or unexpected data that is safely handlederrorfor contract violations or failed operations
Production-visible logs must not include sensitive payloads such as prompts, tool input/output, file contents, command bodies, tokens, secrets, or raw provider requests/responses. If such payloads are needed for local debugging, they must be behind explicit development-only guards and never enabled by default.
Architecture
For detailed background and design decisions, see ARCHITECTURE.md.
Cargo workspace organized in four layers: Foundation → Capability → Domain → Composition. Dependencies flow strictly downward.
Crate Hierarchy & Dependencies
- ✅ Upper layers may depend on lower layers (including cross-layer)
- ✅ Same-layer interaction through trait abstractions only
- ❌ No lower-layer depending on upper-layer
- ❌ No circular dependencies
- Changes to foundation crates require impact assessment
Domain Crate Structure
Every domain crate must follow:
lib.rs— module exports only, no business logicroutes.rs— exportdomain_routes(state) -> Router, handlers do request/response transformation onlyservice.rs— sole location for business logic, must not import axumstate.rs—#[derive(Clone)]RouterState holding Arc-wrapped dependencies
API Conventions
- Route prefix:
/api/ - Resource names: kebab-case
- Response format:
ApiResponse<T>(success) /ErrorResponse(failure) - All request/response types defined in
aionui-api-types aionui-api-typesmust NOT depend on axum/tower or any HTTP framework- Use
aionui_common::ApiErroronly at API/HTTP boundaries such as routes and middleware. Service/domain code must prefer crate-owned errors (ConversationError,TeamError, etc.) and map them toApiErrorin route modules. Do not introduce newAppErrorusages; it exists only as a temporary compatibility alias.
WebSocket Events
- Format:
domain.camelCaseAction(two-level structure) - Message type:
WebSocketMessage<T>(name + data) - Existing kebab-case or three-level names are legacy — new events must follow the convention
Data Layer
- Repository traits in
aionui-db, prefixed withI - Concrete implementations prefixed with
Sqlite - Row models in
aionui-db/src/models/ - Params objects co-located in repository files
- Migrations:
NNN_descriptive_name.sql, no manual DB modifications - Services depend on traits, never on concrete implementations
Dependency Injection
AppServicesis the sole service construction center- Domain crates only define RouterState, never construct their own dependencies
- All assembly happens in
aionui-app'sbuild_*_state()functions
Security
- New endpoints must be evaluated for auth middleware requirement
- State-changing operations must be CSRF-protected
- Sensitive operations should have rate limiting
- Error responses must not leak internal details
- Secrets must never be hardcoded
Code Style
- Rust 2024 edition, stable toolchain (pinned in
rust-toolchain.toml) - Comments in English, commit messages in English
- Each
.rsfile follows single responsibility — one module, one concern - Max 1000 lines per
.rsfile; split into submodules when approaching the limit
Development Workflow
Subprocess Spawning
New subprocess spawn sites must use aionui_runtime::Builder::agent(program) or aionui_runtime::Builder::clean_cli(program). Do NOT use raw tokio::process::Command. See ARCHITECTURE.md § Runtime Infrastructure for details.
Pushing Code
Always use just push instead of git push.
It runs fmt → clippy → test before pushing, preventing CI failures.
Supports the same arguments as git push (e.g. just push -u origin feat/branch).
Add Endpoint to Existing Crate
- Request/response types →
aionui-api-types/src/{domain}.rs - Handler function →
crates/aionui-{domain}/src/routes.rs - Business logic →
crates/aionui-{domain}/src/service.rs - Register route in
domain_routes()function - Add test →
crates/aionui-{domain}/tests/orcrates/aionui-app/tests/
Add Migration
- Next number →
ls crates/aionui-db/migrations/ - Create
NNN_descriptive_name.sqlwithIF NOT EXISTS
Add WebSocket Event
- Event type →
aionui-api-types - Emit via
event_bus.broadcast()in service - Naming:
domain.camelCaseAction
Test Organization
| Location | What goes there |
|---|---|
Inline #[cfg(test)] in each .rs file |
Unit tests for that module's internals |
crates/<crate>/tests/ |
Integration / E2E tests for that crate |
Testing Rules
- Database tests use
init_database_memory() - Prefer real in-memory DB over mocks; mock only to isolate unneeded dependencies
- New features must include tests
Test Scope Requirements
Happy Path (Critical Paths)
Every new or modified feature must have integration tests covering its normal flow. Critical paths that always require test coverage:
- Authentication flow (login, token refresh, permission checks)
- Message sending and retrieval
- Agent session creation and interaction
- File upload/download
- WebSocket connection and event delivery
Bad Path (Error Paths)
New endpoints or business logic must include tests for these scenarios:
- Invalid input (missing fields, wrong types, oversized content)
- Resource not found (404)
- Insufficient permissions (unauthenticated, accessing another user's resources)
- Business rule violations (duplicate creation, operations not allowed in current state)
Bad path tests must assert specific error codes or error messages — asserting merely "not success" is not acceptable.
Security Tests
Endpoints involving authentication, authorization, or data isolation must include security tests:
- Unauthenticated requests are rejected (401)
- Cross-user data isolation (user A cannot access user B's resources)
- State-changing requests are rejected when CSRF token is missing or invalid
- Sensitive fields (passwords, tokens) never appear in responses
WebSocket Event Tests
New WebSocket events must verify:
- The event is emitted after the correct business operation
- Event payload conforms to
WebSocketMessage<T>structure - Events are only delivered to authorized subscribers (no leakage to unrelated users)
Test Failure Handling
When a test fails, do NOT modify the test to make it pass. First determine:
- Test assertion still represents correct behavior → fix implementation, not the test
- Requirements/interface intentionally changed → may update test, but must confirm:
- The change is intentional (not an unintended side effect)
- New assertions still validate meaningful behavior
- Uncertain → stop, trace back the change, clarify before proceeding
Prohibited:
- ❌ Deleting failing tests to "fix" the problem
- ❌ Weakening specific assertions to vague ones (e.g.,
assert_eq!(status, 201)→assert!(status.is_success()))
Verification Strategy
⚠️ When to run what:
- During development: only test the crate you're working on →
cargo test -p aionui-<crate>- After implementation complete: full verification →
cargo test --workspace- Do NOT run
cargo test --workspaceat the start of a task.⚠️ Performance:
cargo clippy --workspacetakes several minutes — userun_in_background: true.cargo test --workspacetakes 10+ minutes. MUST userun_in_background: truewhen calling via Bash tool, otherwise it will timeout.cargo clippy -p aionui-<crate>andcargo test -p aionui-<crate>typically complete in under 1 minute.
During Development (fast feedback loop)
cargo test -p aionui-<crate> # Test the crate you changed
cargo clippy -p aionui-<crate> -- -D warnings # Lint the crate you changed
Before Commit (affected crates)
cargo fmt --all -- --check # Format gate (instant)
cargo clippy -p aionui-<crate1> -p aionui-<crate2> -- -D warnings # Lint affected crates
cargo test -p aionui-<crate1> -p aionui-<crate2> # Test affected crates
Before Push (full workspace)
just push # fmt → clippy → test → git push