Skip to content

Add .github/copilot-instructions.md#744

Open
jerrysxie wants to merge 1 commit intoOpenDevicePartnership:mainfrom
jerrysxie:add-copilot-instructions
Open

Add .github/copilot-instructions.md#744
jerrysxie wants to merge 1 commit intoOpenDevicePartnership:mainfrom
jerrysxie:add-copilot-instructions

Conversation

@jerrysxie
Copy link
Contributor

Add Copilot instructions covering build/test/lint commands, service architecture patterns, and key codebase conventions.

Add Copilot instructions covering build/test/lint commands,
service architecture patterns, and key codebase conventions.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@jerrysxie jerrysxie self-assigned this Mar 9, 2026
@jerrysxie jerrysxie added the enhancement New feature or request label Mar 9, 2026
Copilot AI review requested due to automatic review settings March 9, 2026 16:51
@jerrysxie jerrysxie requested a review from a team as a code owner March 9, 2026 16:51
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds a new .github/copilot-instructions.md document intended to guide Copilot (and contributors) on how to build/test/lint the workspace and on key architecture/convention details for the embedded-services codebase.

Changes:

  • Introduces a Copilot instruction doc with common build/lint/test commands aligned to CI workflows.
  • Documents service/IPC architecture concepts (comms endpoints, message routing) and core utilities/macros.
  • Captures conventions around feature flags, clippy strictness, dependencies, and testing.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +56 to +62
Each service crate follows a consistent structure:

1. **Service struct** with a `comms::Endpoint` and domain-specific context/state
2. **`MailboxDelegate` impl** — the `receive()` method handles incoming messages using type-safe downcasting via `message.data.get::<T>()`
3. **Global singleton** — services are stored in `OnceLock<Service>` statics
4. **Async task function** — registers the endpoint, then loops calling a `process()` or `process_next()` method
5. **Spawned via Embassy** — `#[embassy_executor::task]` functions are spawned from main
Copy link

Copilot AI Mar 9, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The “Service Pattern” section describes a single comms/Endpoint + MailboxDelegate-based structure as if it applies to every service crate. In this repo, some services (e.g., type-c-service) use other IPC patterns (pubsub/broadcaster, ipc::deferred) and don’t have a comms::Endpoint field. Consider rewording this section to describe the comms-based pattern as common (not universal) and call out the alternative patterns used elsewhere in the workspace.

Copilot uses AI. Check for mistakes.

pub async fn task() {
let service = SERVICE.get_or_init(MyService::new);
comms::register_endpoint(service, &service.endpoint).await.unwrap();
Copy link

Copilot AI Mar 9, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The service skeleton example uses .await.unwrap() when registering the endpoint, but later this doc states clippy denies unwrap_used/no panicking in production code. To avoid sending mixed signals, update the example to handle the Result explicitly (e.g., propagate or log/return) rather than unwrapping.

Suggested change
comms::register_endpoint(service, &service.endpoint).await.unwrap();
if let Err(err) = comms::register_endpoint(service, &service.endpoint).await {
// TODO: handle registration error (e.g., log and return or trigger a safe reset)
return;
}

Copilot uses AI. Check for mistakes.

```shell
# ARM board examples
cd examples/rt685s-evk && cargo clippy --target thumbv8m.main-none-eabihf --locked
Copy link

Copilot AI Mar 9, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The examples build/lint section omits the examples/rt633 workspace, which is present in the repo and is also checked in CI. Add an example command for examples/rt633 (or generalize the instructions to cover all examples/* workspaces).

Suggested change
cd examples/rt685s-evk && cargo clippy --target thumbv8m.main-none-eabihf --locked
cd examples/rt685s-evk && cargo clippy --target thumbv8m.main-none-eabihf --locked
cd examples/rt633 && cargo clippy --target thumbv8m.main-none-eabihf --locked

Copilot uses AI. Check for mistakes.
Comment on lines +132 to +133
- Custom `enum` error types per module — no `thiserror` (it requires std)
- All error enums derive `Debug, Clone, Copy, PartialEq, Eq`
Copy link

Copilot AI Mar 9, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The error-handling conventions are stated too strongly: not all error types are enums and not all derive Clone, Copy, PartialEq, Eq (e.g., some error enums only derive Debug/Copy, and some services use a struct error). Consider changing this to “prefer” these derives when practical, and note that some modules use lightweight struct errors.

Suggested change
- Custom `enum` error types per module — no `thiserror` (it requires std)
- All error enums derive `Debug, Clone, Copy, PartialEq, Eq`
- Prefer custom `enum` error types per module — no `thiserror` (it requires std); some modules instead use lightweight struct error types when that is a better fit
- Prefer deriving `Debug, Clone, Copy, PartialEq, Eq` on error enums when practical (some errors may only derive a subset, e.g., `Debug`/`Copy`)

Copilot uses AI. Check for mistakes.
Comment on lines +154 to +156
- Async tests use `embassy_futures::block_on(async { ... })`
- Dev-dependencies enable `std` features: `embassy-sync/std`, `embassy-time/std`, `critical-section/std`
- `tokio` with `rt`, `macros`, `time` features for integration tests
Copy link

Copilot AI Mar 9, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Testing guidance says async tests use embassy_futures::block_on(async { ... }), but there are many async unit tests written with #[tokio::test] in this repo. It would be more accurate to mention both patterns and when each is used.

Suggested change
- Async tests use `embassy_futures::block_on(async { ... })`
- Dev-dependencies enable `std` features: `embassy-sync/std`, `embassy-time/std`, `critical-section/std`
- `tokio` with `rt`, `macros`, `time` features for integration tests
- Async unit tests in `no_std`/Embassy-focused crates use `embassy_futures::block_on(async { ... })` to stay runtime-agnostic
- Host-only async tests and integration tests may use `#[tokio::test]` in crates that depend on `tokio`
- Dev-dependencies enable `std` features: `embassy-sync/std`, `embassy-time/std`, `critical-section/std`
- `tokio` with `rt`, `macros`, `time` features is used to support `#[tokio::test]`-based host/integration tests

Copilot uses AI. Check for mistakes.

### Core Utilities (embedded-service crate)

- **`GlobalRawMutex`**: `ThreadModeRawMutex` on ARM bare-metal, `CriticalSectionRawMutex` in tests/std
Copy link

Copilot AI Mar 9, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

GlobalRawMutex is described as ThreadModeRawMutex on ARM bare-metal and CriticalSectionRawMutex in tests/std, but the actual cfg also selects CriticalSectionRawMutex on riscv32. Consider mentioning that exception to avoid confusing cross-target contributors.

Suggested change
- **`GlobalRawMutex`**: `ThreadModeRawMutex` on ARM bare-metal, `CriticalSectionRawMutex` in tests/std
- **`GlobalRawMutex`**: `ThreadModeRawMutex` on ARM bare-metal, `CriticalSectionRawMutex` on RISC-V bare-metal and in tests/std

Copilot uses AI. Check for mistakes.
Copy link
Contributor

@kurtjd kurtjd left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll be honest I'm still not entirely sure what these instructions offer if they are AI generated in the first place (I thought things like skills, AGENTS.md, CLAUDE.md, etc are to provide additional context the LLM can't glean on it's own from the codebase) but that likely means I just need to research this a bit more.

@jerrysxie
Copy link
Contributor Author

I'll be honest I'm still not entirely sure what these instructions offer if they are AI generated in the first place (I thought things like skills, AGENTS.md, CLAUDE.md, etc are to provide additional context the LLM can't glean on it's own from the codebase) but that likely means I just need to research this a bit more.

@kurtjd It is more like breadcrumbs to help the agent to find its way. Unless we commit something to AI agent's memory, it will need to rediscover the context every single time when we open a new session. Instruction file helps AI to find its way faster. We can also add contributing policy to the instruction file so agent would follow our guidelines.

@kurtjd
Copy link
Contributor

kurtjd commented Mar 11, 2026

I'll be honest I'm still not entirely sure what these instructions offer if they are AI generated in the first place (I thought things like skills, AGENTS.md, CLAUDE.md, etc are to provide additional context the LLM can't glean on it's own from the codebase) but that likely means I just need to research this a bit more.

@kurtjd It is more like breadcrumbs to help the agent to find its way. Unless we commit something to AI agent's memory, it will need to rediscover the context every single time when we open a new session. Instruction file helps AI to find its way faster. We can also add contributing policy to the instruction file so agent would follow our guidelines.

Okay that makes sense to me. Yeah I suppose we just need to be careful since embedded-services patterns and architecture are changing pretty frequently and don't want this to drift too far from the actual state of the repo. Maybe a rolling workflow can have Copilot regenerate this every so often or just have a rule that PRs introducing significant changes need to update this as well.


Each service crate follows a consistent structure:

1. **Service struct** with a `comms::Endpoint` and domain-specific context/state
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we're in the process of making 1-3 here not true; we've already migrated a bunch of services away from the comms system and out of OnceLock statics. May want to just remove those pieces


### Communication (IPC)

Services communicate through `embedded_services::comms` — a type-erased message routing system built on intrusive linked lists (zero allocation):
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same here - comms system is going away

@jerrysxie jerrysxie moved this to In progress in ODP Backlog Mar 12, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

Status: In progress

Development

Successfully merging this pull request may close these issues.

4 participants