Annotations
Skills are described using @skill:* comment annotations. The lmsk generate tool reads them and produces dispatch code.
Annotation format by language
Each language uses its own comment syntax:
- AssemblyScript
- Go
- Rust
Crate-level annotations use JSDoc comments (/** */) before the first export. Method annotations use // comments directly above the function.
/**
* @skill:id ai.luminarys.as.my-skill
* @skill:name "My Skill"
* @skill:version 1.0.0
* @skill:desc "Skill description."
*/
import { Context } from "@luminarys/sdk-as";
// @skill:method greet "Greet by name."
// @skill:param name required "User name"
// @skill:result "Greeting text"
export function greet(_ctx: Context, name: string): string {
return "Hello, " + name + "!";
}
All annotations must be doc comments directly before package main — no blank line between the last annotation and package main. Method annotations use // comments above the function.
// @skill:id ai.luminarys.go.my-skill
// @skill:name "My Skill"
// @skill:version 1.0.0
// @skill:desc "Skill description."
package main
import sdk "github.com/LuminarysAI/sdk-go"
// @skill:method greet "Greet by name."
// @skill:param name required "User name"
// @skill:result "Greeting text"
func Greet(ctx *sdk.Context, name string) (string, error) {
return "Hello, " + name + "!", nil
}
If there is a blank line between annotations and package main, the Go parser will not find the annotations.
Crate-level annotations use //! doc comments (inner doc) or /// doc comments at the top of skill.rs. Method annotations use /// directly above the function.
/// @skill:id ai.luminarys.rust.my-skill
/// @skill:name "My Skill"
/// @skill:version 1.0.0
/// @skill:desc "Skill description."
use luminarys_sdk::prelude::*;
/// @skill:method greet "Greet by name."
/// @skill:param name required "User name"
/// @skill:result "Greeting text"
pub fn greet(_ctx: &mut Context, name: String) -> Result<String, SkillError> {
Ok(format!("Hello, {}!", name))
}
Skill identity
| Annotation | Required | Description |
|---|---|---|
@skill:id | Yes | Reverse-domain format, at least 3 segments (e.g. ai.luminarys.rust.echo) |
@skill:name | Yes | Display name (quoted string) |
@skill:version | Yes | Semver: X.Y.Z |
@skill:desc | No | Description shown in tool listings |
ID format rules
- At least 3 dot-separated segments:
ai.luminarys.echo(valid),echo-skill(invalid) - Each segment: lowercase letters, digits, hyphens
- No leading/trailing hyphens, no empty segments
Methods
@skill:method <name> "<description>"
@skill:param <name> [required] "<description>"
@skill:result "<description>"
- Method name:
snake_case— letters, digits, underscores - Parameter name: must match the function argument name
requiredmakes the parameter mandatory — omitting it returns an error@skill:resultis documentation only (does not affect behavior)
Supported parameter types
| Type | Go | Rust | AssemblyScript |
|---|---|---|---|
| string | string | String | string |
| integer | int64 | i64 | i64 |
| float | float64 | f64 | f64 |
| boolean | bool | bool | bool |
| bytes | []byte | Vec<u8> | Uint8Array |
Modifiers
@skill:internal
Hides the method from tool listings. Still callable by other skills via inter-skill invocation.
@skill:callback
Marks a method as a private callback. Hidden from tool listings, only callable by the owning skill (used for TCP/WebSocket push callbacks).
Permission requirements
@skill:require fs /data/shared rw
@skill:require http https://api.example.com/**
@skill:require shell go **
@skill:require tcp *:5432
@skill:require env API_KEY
Requirements are embedded in the skill package and validated at load time. If the deployment manifest doesn't satisfy a requirement, the skill won't load.
This ensures that a skill always declares what it needs — and the operator explicitly grants it in the manifest.