docs: add architecture notes and development principles

This commit is contained in:
2026-07-14 17:19:31 +08:00
parent 43edb12d6a
commit 123aadeadf
3 changed files with 149 additions and 0 deletions
+60
View File
@@ -0,0 +1,60 @@
# CLAUDE.md
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
## Project overview
Plyngent is an LLM chat and agent toolkit (Python 3.14+, PDM-managed). It is in early development — core protocol clients exist, while agent, CLI, web, memory, and config modules are planned but not yet implemented.
## Commands
```bash
pdm install # first-time dependency setup
pdm sync # sync after pulling changes
pdm run basedpyright . # type checking (basedpyright, "recommended" strictness)
pdm run ruff check . # linting
pdm run ruff format . # formatting
```
There is no test runner configured yet.
## Architecture
### Data modeling: `msgspec.Struct`
All protocol models use `msgspec.Struct` — not dataclasses, not Pydantic. This gives type-safe, schema-validated structs with efficient JSON codec support. Use `msgspec.field(default=UNSET)` for optional fields to distinguish "not provided" from `None`.
The `Unset` type alias (`typedef.py`) wraps `msgspec.UNSET` as `Literal[UnsetType.UNSET]`. `JSONSchema` is `dict[str, Any]`.
### Protocol layering (`lmproto/`)
```
lmproto/openai_compatible/ ← Base: model, config, client
lmproto/deepseek/openai_compat/ ← Extends base via inheritance + extra fields
```
- **`openai_compatible/model.py`** — chat message models (`SystemChatMessage`, `UserChatMessage`, `AssistantChatMessage`, `ToolChatMessage`), tool definitions, request/response structs, streaming chunks. All `msgspec.Struct` with `rename="snake"` for camelCase JSON interop.
- **`openai_compatible/client.py`** — `BaseOpenAIClient` using `niquests` for async HTTP with SSE streaming. Two response modes: `ChatCompletionResponse` (non-streaming) and `AsyncIterator[ChatCompletionChunk]` (streaming).
- **`openai_compatible/config.py`** — `OpenAIConfig` dataclass (base URL, API key, model name, max tokens, temperature).
- **DeepSeek extension** — `DeepseekOpenAIClient` extends `BaseOpenAIClient`. Models add `reasoning_content`, `prefix`, `ThinkingOptions`, and `DeepSeekReasoningEffort` (including `"max"`).
### Composition utility: `Forward` descriptor
`utils/components.py` provides a `Forward[T]` descriptor for forwarding attribute access to a composed sub-object — prefer composition over inheritance where appropriate. The `forward()` factory function constructs `Forward` instances with type inference.
### Type annotations are mandatory
Basedpyright in `recommended` mode (strictest preset). Ruff lint rules include `ANN` (flake8-annotations) — all functions must have type annotations except private functions (`ANN202` suppressed). Use PEP 695 `type X = ...` syntax for type aliases. Python 3.14+ generics syntax is expected.
## Commit messages
Scoped commit messages, not conventional commits:
```
<scope>: <brief description>
```
Examples: `deps: add fastapi`, `core/mq: fix incorrect message sending`, `router: add routing service for xxx`, `test/webserver: change test client`, `ci/lint: run ruff style check`.
Check `git log` for the full convention.
+29
View File
@@ -0,0 +1,29 @@
# Code Architecture
- plyngent
- typedef: Shared type aliases.
- lmproto: Protocols for interacting with LLM service.
- (common)
- model: Messages models of specified providers.
- config: Configurations for specified providers.
- client: Clients for accessing existent specified services.
- server: Servers for accepting other clients.
- openai
- openai_compatible
- anthropic
- ollama
- deepseek
- openai_compat
- anthropic
- utils: Common utilities for code architecture.
- components: Utilities for class composition.
- memory: Storage controlling for sessions and messages.
- router: Multi-source capability routing and interception.
- interceptors: Capability of stealing a few arguments for partial re-routing.
- ...
- config: Plyngent configuration center.
- agent: Agent capabilities and controlling.
- tools: Client code of tool calls.
- cli: CLI for chat/agent application.
- web: Web service for chat/agent application.
+60
View File
@@ -0,0 +1,60 @@
# Development Principles
## If you are new to project
### Have a general overview of the project
You should at least have a clear view of the general architecture. This aims for:
1. keeping the style of codebase consistent.
2. using or extending existing objects or functions instead of writing new but duplicate code, since the latter is usually a kind of **SHIT**.
For a general architecture reference, see [here](./architecture.md).
This does not mean you should immediately grasp the whole codebase, but **you should not make changes until you have a clear view of the general architecture**.
### Commit messages
This project uses scoped commit message. Examples:
- `project: init`: initializing a new project.
- `deps: add fastapi`: add/upgrade/removing a dependency.
- `deps/dev: upgrade ruff`: add/upgrade/removing a dev dependency.
- `core/mq: fix incorrect message sending`, `router: add routing service for xxx`: add/change/fix/refactor/removing functional code.
- `test/webserver: change test client to niquests`: add/change/fix/refactor/removing tests.
- `scripts/i18n: implement dumping translation keys`: add/change/fix/refactor/removing general scripts.
- `ci/lint: run ruff style check`, `ci/build: fix changelog generation`: add/change/fix/refactor/removing CI workflows.
Once conventional commit was good, until redundant forms like `fix: fix ...`, `refactor: refactor ...` came up. So we use scoped commit message here.
If you are still not quite familiar to this, check the git log in any way you prefer.
## General information and suggestions
### Local development environment
Syncing packages: `pdm install` the first time, then `pdm sync`. The former can fully initialize the dependencies, and the latter can continuously keep consistent dependencies.
For other commands like adding or removing packages, see [PDM Documentation](https://pdm-project.org/en/latest/usage/dependency/). These commands usually updates lock file automatically by default, so `pdm sync` should only be used when after `git pull/fetch/checkout`.
### Type checking and linting
Firstly, we prefer using `pdm run <command/script>` to directly running commands in venv (whether in activated environment or not).
Then for every projects, check the dev dependency group where you can find tools used for type checking and linting.
Type checking: `pdm run basedpyright .`
Linting: `pdm run ruff check .`
Formating: `pdm run ruff format .`
<!-- Contents in comments are for projects with long-period developments, but this is a new project.
### Branches
In most cases, we do not need and should not make bare commits on the main branch.
### Tests
...
-->