@antprofuse/saddle-skill 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/SKILL.md +26 -0
- package/agents/openai.yaml +4 -0
- package/package.json +15 -0
- package/references/service-0.1.1.md +163 -0
package/SKILL.md
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: saddle-service
|
|
3
|
+
description: Build and review minimal Rust Service applications against the published Saddle facade package `saddle-framework = "=0.1.1"`. Use when Codex needs to create a Saddle 0.1.1 Service contract, handler, registration, HTTP/JSON exposure, fixed process entry, or verify generated business code without reading or changing Saddle middleware implementation.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Saddle Service 0.1.1
|
|
7
|
+
|
|
8
|
+
Use only the public API shipped by `saddle-framework = "=0.1.1"`.
|
|
9
|
+
|
|
10
|
+
## Workflow
|
|
11
|
+
|
|
12
|
+
1. Pin the facade exactly as `saddle-framework = "=0.1.1"`; import it as `saddle`.
|
|
13
|
+
2. Read [references/service-0.1.1.md](references/service-0.1.1.md) before generating Service code.
|
|
14
|
+
3. Start from the verified `examples/helloworld` consumer when working in the Saddle repository.
|
|
15
|
+
4. Keep business code limited to request/response types, a Service contract, its handler, and Saddle assembly.
|
|
16
|
+
5. Run both the Rust 1.85 and current-toolchain checks documented in [references/service-0.1.1.md](references/service-0.1.1.md) after changing the reference example.
|
|
17
|
+
6. Reject APIs that are only described as V1 goals but are absent from the published facade.
|
|
18
|
+
|
|
19
|
+
## Boundaries
|
|
20
|
+
|
|
21
|
+
- Do not inspect or modify Saddle component implementation.
|
|
22
|
+
- Do not replace Saddle's process entry, async runtime, HTTP server, database pool, or observability setup.
|
|
23
|
+
- Do not create threads, runtimes, detached tasks, routers, I/O clients, or DB pools in business code.
|
|
24
|
+
- Do not claim DB, transaction, internal Service call, graceful shutdown, or observability usage patterns without a compiling 0.1.1 consumer.
|
|
25
|
+
- If a required public API is missing, preserve a minimal reproducible consumer failure and submit it through remote Git for the control workspace to assess. Do not patch middleware here.
|
|
26
|
+
- Treat local design documents as intent and crates.io 0.1.1 compilation as the source of truth for usable API.
|
package/package.json
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@antprofuse/saddle-skill",
|
|
3
|
+
"version": "0.1.1",
|
|
4
|
+
"description": "AI Coding skill for building verified Saddle 0.1.1 Service applications.",
|
|
5
|
+
"license": "MIT OR Apache-2.0",
|
|
6
|
+
"files": [
|
|
7
|
+
"SKILL.md",
|
|
8
|
+
"agents",
|
|
9
|
+
"references"
|
|
10
|
+
],
|
|
11
|
+
"publishConfig": {
|
|
12
|
+
"access": "public",
|
|
13
|
+
"registry": "https://registry.npmjs.org/"
|
|
14
|
+
}
|
|
15
|
+
}
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
# Saddle Service 0.1.1 contract
|
|
2
|
+
|
|
3
|
+
## Dependency
|
|
4
|
+
|
|
5
|
+
Use the published facade package at an exact version:
|
|
6
|
+
|
|
7
|
+
```toml
|
|
8
|
+
[package]
|
|
9
|
+
edition = "2024"
|
|
10
|
+
rust-version = "1.85"
|
|
11
|
+
|
|
12
|
+
[dependencies]
|
|
13
|
+
saddle-framework = "=0.1.1"
|
|
14
|
+
serde = { version = "1", features = ["derive"] }
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
The Cargo package is `saddle-framework`; the Rust library name is `saddle`.
|
|
18
|
+
|
|
19
|
+
## Correct minimal pattern
|
|
20
|
+
|
|
21
|
+
Define one zero-sized contract type, serializable request/response types, and a separate handler:
|
|
22
|
+
|
|
23
|
+
```rust
|
|
24
|
+
use saddle::{
|
|
25
|
+
CallContext,
|
|
26
|
+
service::{Service, ServiceFuture, ServiceHandler},
|
|
27
|
+
};
|
|
28
|
+
use serde::{Deserialize, Serialize};
|
|
29
|
+
|
|
30
|
+
struct Hello;
|
|
31
|
+
|
|
32
|
+
#[derive(Deserialize)]
|
|
33
|
+
struct HelloRequest {
|
|
34
|
+
name: String,
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
#[derive(Serialize)]
|
|
38
|
+
struct HelloResponse {
|
|
39
|
+
message: String,
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
impl Service for Hello {
|
|
43
|
+
type Request = HelloRequest;
|
|
44
|
+
type Response = HelloResponse;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
struct HelloHandler;
|
|
48
|
+
|
|
49
|
+
impl ServiceHandler<Hello> for HelloHandler {
|
|
50
|
+
fn call<'a>(
|
|
51
|
+
&'a self,
|
|
52
|
+
_context: &'a CallContext,
|
|
53
|
+
request: HelloRequest,
|
|
54
|
+
) -> ServiceFuture<'a, HelloResponse> {
|
|
55
|
+
Box::pin(async move {
|
|
56
|
+
Ok(HelloResponse {
|
|
57
|
+
message: format!("Hello, {}!", request.name),
|
|
58
|
+
})
|
|
59
|
+
})
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
Register and expose it only through Saddle:
|
|
65
|
+
|
|
66
|
+
```rust
|
|
67
|
+
builder.register::<Hello, _>(
|
|
68
|
+
ServiceDescriptor::new("helloworld", "hello", "say_hello"),
|
|
69
|
+
HelloHandler,
|
|
70
|
+
)?;
|
|
71
|
+
builder.expose_json::<Hello>("/hello");
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
Use the fixed process entry:
|
|
75
|
+
|
|
76
|
+
```rust
|
|
77
|
+
let database_url = std::env::var("SADDLE_DATABASE_URL")
|
|
78
|
+
.expect("SADDLE_DATABASE_URL must be set by deployment configuration");
|
|
79
|
+
let config = SaddleConfig::new("helloworld", database_url, listen);
|
|
80
|
+
|
|
81
|
+
Saddle::run(config, |builder| {
|
|
82
|
+
// Register and expose Services here.
|
|
83
|
+
Ok(())
|
|
84
|
+
})
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
See `examples/helloworld` for the complete compiling consumer.
|
|
88
|
+
|
|
89
|
+
## Incorrect patterns
|
|
90
|
+
|
|
91
|
+
Do not use an unpinned or compatible version range:
|
|
92
|
+
|
|
93
|
+
```toml
|
|
94
|
+
# Wrong: 0.1.x may change incompatibly.
|
|
95
|
+
saddle-framework = "0.1"
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
Do not embed database credentials or provide an insecure fallback:
|
|
99
|
+
|
|
100
|
+
```rust
|
|
101
|
+
// Wrong: canonical examples must not normalize secrets in source.
|
|
102
|
+
let database_url = "mysql://user:password@127.0.0.1/application";
|
|
103
|
+
|
|
104
|
+
// Wrong: a missing deployment value must fail instead of silently using credentials.
|
|
105
|
+
let database_url = std::env::var("SADDLE_DATABASE_URL")
|
|
106
|
+
.unwrap_or_else(|_| "mysql://user:password@127.0.0.1/application".into());
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
Do not import Service traits from the facade root:
|
|
110
|
+
|
|
111
|
+
```rust
|
|
112
|
+
// Wrong in 0.1.1: these are under saddle::service.
|
|
113
|
+
use saddle::{Service, ServiceHandler};
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
Do not implement business execution with Tokio or Axum:
|
|
117
|
+
|
|
118
|
+
```rust
|
|
119
|
+
// Wrong: business code must not own the runtime or HTTP server.
|
|
120
|
+
#[tokio::main]
|
|
121
|
+
async fn main() {}
|
|
122
|
+
|
|
123
|
+
tokio::spawn(async move {});
|
|
124
|
+
axum::Router::new();
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
Do not invent ergonomic macros or async trait syntax that 0.1.1 does not publish:
|
|
128
|
+
|
|
129
|
+
```rust
|
|
130
|
+
// Wrong: not verified public APIs in 0.1.1.
|
|
131
|
+
#[saddle::service]
|
|
132
|
+
async fn hello(...) { ... }
|
|
133
|
+
|
|
134
|
+
#[saddle::main]
|
|
135
|
+
async fn main() { ... }
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
Do not create a registry or database directly:
|
|
139
|
+
|
|
140
|
+
```rust
|
|
141
|
+
// Wrong: assembly and managed I/O construction belong to Saddle.
|
|
142
|
+
let registry = saddle::service::ServiceRegistryBuilder::new();
|
|
143
|
+
let database = saddle::db::Database::connect(...);
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
## Validation
|
|
147
|
+
|
|
148
|
+
Run:
|
|
149
|
+
|
|
150
|
+
```bash
|
|
151
|
+
cargo +1.85.0 check --locked --manifest-path examples/helloworld/Cargo.toml
|
|
152
|
+
cargo check --locked --manifest-path examples/helloworld/Cargo.toml
|
|
153
|
+
cargo tree --locked --manifest-path examples/helloworld/Cargo.toml \
|
|
154
|
+
-p saddle-framework@0.1.1
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
Current verified result:
|
|
158
|
+
|
|
159
|
+
- The Rust 1.85 and current-toolchain checks compile against the crates.io `saddle-framework 0.1.1` artifact.
|
|
160
|
+
- The dependency tree resolves every Saddle component to 0.1.1.
|
|
161
|
+
- The lockfile is resolved with Cargo 1.85's incompatible-Rust-version fallback so every selected package supports the declared minimum.
|
|
162
|
+
|
|
163
|
+
The example does not prove runtime readiness because `SADDLE_DATABASE_URL` must identify a reachable database and the configured listen address must be available.
|