Skill Development
This guide walks through building a Komand skill from project creation to packaging.
Prerequisites
Section titled “Prerequisites”- .NET 10 SDK — download
- Komand SDK NuGet package —
Komand.Sdk - A Komand instance for integration testing (local or managed)
1. Create a Project
Section titled “1. Create a Project”Using the SDK template:
dotnet new komand-skill -n MySkillcd MySkillOr manually:
dotnet new classlib -n MySkillcd MySkilldotnet add package Komand.SdkThe template scaffolds:
MySkill/├── MySkill.csproj├── MySkill.cs # Skill implementation├── Models/│ ├── MySkillInput.cs # Input record│ └── MySkillOutput.cs # Output record├── Tests/│ └── MySkillTests.cs # Unit tests└── skill.json # Marketplace metadata2. Define the Contract
Section titled “2. Define the Contract”Every skill implements IKomandSkill and exposes a SkillDefinition:
public class ContactLookupSkill : IKomandSkill{ public SkillDefinition Definition => new() { SkillId = "my-contact-lookup", Name = "Contact Lookup", Description = "Search contacts by name or email", Version = "1.0.0", PublisherId = "your-publisher-id", InputSchema = JsonSchema.FromType<ContactSearchInput>(), OutputSchema = JsonSchema.FromType<ContactSearchOutput>(), RequiredPermissions = ["crm:read"], DeclaredToolAccess = ["database"] };}Contract Fields
Section titled “Contract Fields”| Field | Required | Description |
|---|---|---|
SkillId | Yes | Unique identifier, lowercase with hyphens |
Name | Yes | Human-readable display name |
Description | No | What the skill does (shown to agents and users) |
Version | Yes | Semantic version (major.minor.patch) |
PublisherId | Yes | Your publisher ID from the marketplace |
InputSchema | No | JSON Schema for the input the skill accepts |
OutputSchema | No | JSON Schema for the output the skill returns |
RequiredPermissions | No | Permissions the skill needs to function (defaults to empty) |
DeclaredToolAccess | No | Platform tools the skill may invoke |
3. Define Input and Output
Section titled “3. Define Input and Output”Use C# records for immutable, schema-friendly data models:
public record ContactSearchInput( string Query, int MaxResults = 10);
public record ContactSearchOutput( IReadOnlyList<Contact> Contacts, int TotalCount);
public record Contact( string Name, string Email, string? Phone);The SDK generates JSON Schemas from these types automatically via JsonSchema.FromType<T>(). The platform validates all input against the schema before your code runs.
4. Implement the Logic
Section titled “4. Implement the Logic”public async Task<SkillResult> ExecuteAsync( SkillContext context, CancellationToken ct){ var input = context.GetInput<ContactSearchInput>();
// Validate business rules beyond schema validation if (string.IsNullOrWhiteSpace(input.Query)) return SkillResult.Failure("Search query is required");
if (input.MaxResults is < 1 or > 100) return SkillResult.Failure("MaxResults must be between 1 and 100");
// Execute the actual work var contacts = await SearchContactsAsync(input.Query, input.MaxResults, ct);
return SkillResult.Success(new ContactSearchOutput( Contacts: contacts, TotalCount: contacts.Count ));}SkillContext
Section titled “SkillContext”The SkillContext provides runtime services to your skill:
| Member | Description |
|---|---|
GetInput<T>() | Deserialise and return the validated input |
GetCredential(name) | Retrieve a credential from the secure vault |
Logger | Structured logger scoped to this execution |
CancellationToken | Token that fires when the execution timeout is reached |
SkillResult
Section titled “SkillResult”| Method | When to use |
|---|---|
SkillResult.Success(data) | Execution succeeded, return output |
SkillResult.Failure(message) | Execution failed, return error message |
5. Handle Credentials
Section titled “5. Handle Credentials”Skills never receive raw API keys. Instead, credentials are stored in the platform’s secure vault and accessed through SkillContext:
public async Task<SkillResult> ExecuteAsync( SkillContext context, CancellationToken ct){ var apiKey = context.GetCredential("salesforce-api-key") ?? return SkillResult.Failure("Salesforce API key not configured");
var client = new SalesforceClient(apiKey); // ...}Users configure credentials when they install the skill. The platform injects them at runtime without exposing them to skill code directly.
6. Test Locally
Section titled “6. Test Locally”The SDK provides SkillTestContext for unit testing without a running platform:
using Komand.Sdk.Testing;
public class ContactLookupSkillTests{ private readonly ContactLookupSkill _skill = new();
[Fact] public async Task Execute_WithValidQuery_ReturnsContacts() { // Arrange var context = SkillTestContext.Create( new ContactSearchInput("alice"));
// Act var result = await _skill.ExecuteAsync(context, CancellationToken.None);
// Assert result.IsSuccess.Should().BeTrue(); var output = result.GetOutput<ContactSearchOutput>(); output.Contacts.Should().NotBeEmpty(); }
[Fact] public async Task Execute_WithEmptyQuery_ReturnsFailure() { // Arrange var context = SkillTestContext.Create( new ContactSearchInput(""));
// Act var result = await _skill.ExecuteAsync(context, CancellationToken.None);
// Assert result.IsSuccess.Should().BeFalse(); result.Error.Should().Contain("required"); }
[Theory] [InlineData(0)] [InlineData(101)] public async Task Execute_WithInvalidMaxResults_ReturnsFailure(int maxResults) { var context = SkillTestContext.Create( new ContactSearchInput("alice", maxResults));
var result = await _skill.ExecuteAsync(context, CancellationToken.None);
result.IsSuccess.Should().BeFalse(); }}Testing with Credentials
Section titled “Testing with Credentials”var context = SkillTestContext.Create( new ContactSearchInput("alice"), credentials: new Dictionary<string, string> { ["salesforce-api-key"] = "test-key-for-unit-tests" });7. Package and Publish
Section titled “7. Package and Publish”Package
Section titled “Package”dotnet komand skill packThis creates a .komandskill package containing:
- Compiled skill assembly
skill.jsonmetadata- Input/output schemas
- README and license
Publish
Section titled “Publish”dotnet komand skill publish --api-key YOUR_PUBLISHER_KEYSee the Marketplace page for details on the review process and verification.
Skill Lifecycle
Section titled “Skill Lifecycle”Define → Implement → Test → Package → Publish → Review → Verified- Define — skill contract with input/output schemas and permissions
- Implement — business logic using
SkillContextservices - Test — unit and integration tests using SDK test utilities
- Package — bundle into a
.komandskilldistributable - Publish — upload to the Komand marketplace
- Review — security and quality review by the Komand team
- Verified — approved skills receive a verified badge and signature
Security Constraints
Section titled “Security Constraints”Skills run in a sandboxed environment. This is a core security guarantee — not optional:
| Constraint | Detail |
|---|---|
| File system | No access outside the skill’s temp directory |
| Network | No outbound access unless network:outbound is declared |
| CPU / memory | Hard limits enforced by the container/WASM runtime |
| Timeout | Skills exceeding their timeout are terminated (max 30 minutes) |
| Input validation | All inputs validated against the declared schema before execution |
| Credential isolation | Skills receive scoped credentials, never raw vault access |
Why This Matters
Section titled “Why This Matters”Open-source agent frameworks have well-documented security issues — skills performing data exfiltration, prompt injection vulnerabilities, and uncontrolled resource usage. Komand’s sandbox model prevents these attack vectors by design.
Permission Reference
Section titled “Permission Reference”Common permissions your skill can request:
| Permission | Scope |
|---|---|
network:outbound | Make HTTP requests to external services |
crm:read | Read CRM data (contacts, deals, activities) |
crm:write | Create or modify CRM data |
calendar:read | Read calendar events |
calendar:write | Create or modify calendar events |
email:send | Send emails through the platform |
storage:read | Read files from skill storage |
storage:write | Write files to skill storage |
database | Access the platform database tools |
Request only the permissions your skill actually needs. Excessive permission requests are flagged during review.