Native Shell
Native Shell은 모든 플랫폼의 앱 안에서 만들어지는 AI UI입니다
개인 계정의 공개 저장소 소유자는 GitHub로 로그인해 운영자를 확인하고 소개를 직접 관리할 수 있습니다. 관리자 승인은 필요하지 않습니다.
로그인한 뒤 확인 파일을 만들어 이 저장소의 기본 브랜치에 30분 안에 커밋해 주세요. 다른 브랜치나 포크의 파일은 인정하지 않습니다. 파일을 올린 뒤 아래에서 확인하면 관리자 승인 없이 관리할 수 있습니다. 자격을 유지하려면 파일을 남겨 두세요.
로그인이 필요하면 로그인 화면으로 이동합니다. 로그인 후 이곳으로 돌아와 원하는 확인 버튼을 다시 눌러 주세요.
프로젝트 폴더에서 /nomorevibe verify를 실행하면 소유권을 확인하고 소개를 직접 관리할 수 있습니다.
1분 만에 확인하기Code-defined AI agents and tools for .NET, checked at compile time. Built on Microsoft.Extensions.AI.
저장소 README에서 가져옴
README 전체를 불러오는 중입니다.
README 전문 보기 ↗Code-defined agents and toolsets for .NET 10, built on Microsoft.Extensions.AI.
Documentation · Getting started · Changelog
Build AI agents for .NET with just a few lines of code, and let the compiler catch your mistakes.
[!WARNING] Typeshift is in alpha: the API may change between releases. Status lists what is open.
AddTool(FindCompanies) turns a static method into a tool, and its XML docs become what
the model reads. Group your tools by feature, domain or permission level, as you like.Settings record of what you mark configurable. Store
it in your database, under the id type you already use.IChatClient serves a model, nothing uses reflection, and your app
publishes with Native AOT.dotnet add package Typeshift --prerelease
The types are in the Typeshift namespace, so add using Typeshift; to your files. Turn on XML docs and pick your id
type once, in a Directory.Build.props next to your solution:
<Project>
<PropertyGroup>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
<!-- Ids are Guids unless you name another type -->
<TypeshiftIdType>int</TypeshiftIdType>
</PropertyGroup>
</Project>
A tool is a static method. Its XML docs describe it to the model, and its settings stay out of the model's reach:
internal partial class CompanyToolset : Toolset
{
public CompanyToolset()
{
WithDisplayName("Companies");
AddTool(FindCompanies)
.WithSettings<FindCompaniesSettings>()
.Configurable(s => s.Limit);
}
/// <summary>
/// Finds the companies of a city.
/// </summary>
/// <param name="city">The city the companies are based in.</param>
public static IReadOnlyList<Company> FindCompanies(string city, FindCompaniesSettings settings) =>
[
.. Companies
.Where(company => company.City.Equals(city, StringComparison.OrdinalIgnoreCase))
.Where(company => company.Active || settings.IncludeInactive)
.Take(settings.Limit)
];
private static readonly Company[] Companies =
[
new("Danube Robotics", "Vienna", Active: true),
new("Prater Motion", "Vienna", Active: true),
new("Graz Gearworks", "Graz", Active: false)
];
}
internal sealed record Company(string Name, string City, bool Active);
snippet source | anchor
{
"name": "find_companies",
"description": "Finds the companies of a city.",
"parameters": {
"type": "object",
"properties": {
"city": { "type": "string", "description": "The city the companies are based in." }
},
"required": ["city"]
}
}
The constructor picks the model, the tools and their settings. Configurable names what may change at runtime:
internal partial class ResearchAgent : Agent
{
public ResearchAgent()
{
WithDescription("Researches the companies of a city.");
WithChatOptions()
.WithModel("openai", "gpt-5-mini")
.WithTemperature(0.2f)
.Configurable(o => o.Instructions)
.Configurable(o => o.Temperature);
UseToolset<CompanyToolset>();
ConfigureFindCompanies()
.WithLimit(3);
}
protected override string GetInstructions() =>
"""
Find companies with the find_companies tool and list them.
""";
}
snippet source | anchor
AddTypeshift() registers every toolset and agent. You bring a chat client provider, which returns the IChatClient
of a provider's model, and a store for settings and conversations:
var services = new ServiceCollection();
services.AddTypeshift()
.WithStore<InMemoryTypeshiftStore>()
.WithChatClientProvider<KeyedChatClientProvider>();
services.AddKeyedSingleton<IChatClient>("openai", new CannedChatClient());
await using var provider = services.BuildServiceProvider(validateScopes: true);
snippet source | anchor
CannedChatClient is a fake that lets the samples run without a network. In your app, register a real client in its
place, such as OpenAI's.
internal sealed class KeyedChatClientProvider(IServiceProvider services) : IChatClientProvider
{
// One client per provider serves all its models: Typeshift puts the model into every request
public ValueTask<IChatClient> GetChatClientAsync(string provider, string model, CancellationToken ct) =>
ValueTask.FromResult(
services.GetKeyedService<IChatClient>(provider)
?? throw new InvalidOperationException($"No IChatClient is registered for the provider '{provider}'."));
}
snippet source | anchor
Store settings under an id you own, then run the agent:
await using var scope = provider.CreateAsyncScope();
var research = scope.ServiceProvider.GetRequiredService<AgentHost<ResearchAgent>>();
var settingsId = 42;
await research.ConfigureAsync(settingsId, settings => settings with
{
Temperature = 0.4f,
FindCompanies = settings.FindCompanies with { Limit = 2 }
});
snippet source | anchor
var answer = await research.RunAsync("Vienna", settingsId, conversationId: 1);
Console.WriteLine($"{research.Agent.Name}: {answer.Text}");
snippet source | anchor
The getting started guide explains every line, and lists what your app implements.
| Feature | What it gives you |
|---|---|
| Tool settings | Limits and timeouts the model cannot choose, set in code, per customer or per run |
| Composable agents | Agents built from toolsets, sub-agents and handoffs |
| One store | Settings and conversations in your database, behind four methods |
| Conversations | Resume after a crash, steer a run while it works, watch it live |
| Tool approval | Let your app approve a call before it runs |
| Plan and auto modes | Let the agent plan first, or run without interruptions |
| Middleware | Wrap every run or tool call |
| Context providers | Add memory, documents or other data to every run |
| MCP servers | Offer an MCP server's tools to an agent |
| Long-running agents | Compaction and crash recovery for hundreds of model calls |
A workspace toolset, a background sub-agent, plan mode and compaction, together:
internal partial class CodingAgent : Agent
{
public CodingAgent()
{
WithChatOptions()
.WithModel("anthropic", "claude-sonnet-5-5");
UseToolset<WorkspaceToolset>();
UseAgent<ExploreAgent>()
.InBackground();
WithRunOptions()
.WithMode(AgentMode.Plan)
.WithMaxToolIterations(500)
.WithMaxInputTokens(150_000)
.WithSummaryModel("claude-haiku-5-5")
.Configurable(r => r.Mode)
.Configurable(r => r.MaxToolIterations)
.Configurable(r => r.SummaryModel);
}
protected override string GetInstructions() =>
"""
Work in the customer's workspace. Read before you change anything, and run the tests after every change.
""";
}
snippet source | anchor
Contributions are welcome. The repository is set up for coding agents: AGENTS.md maps each task to its
playbook, and the contributing guide covers building, testing
and the docs. Code may be written with AI. Docs may be drafted with AI, but a person reviews and rewrites them, because
clear docs are what make Typeshift easy to pick up.
| Observability | OpenTelemetry spans and metrics for every run |
| Native AOT | Publish your app without reflection or trim warnings |