();
diff --git a/src/Shared/TeamUp.SharedKernel/Access/AccessPolicy.cs b/src/Shared/TeamUp.SharedKernel/Access/AccessPolicy.cs
index 9fb59eb..05f7c50 100644
--- a/src/Shared/TeamUp.SharedKernel/Access/AccessPolicy.cs
+++ b/src/Shared/TeamUp.SharedKernel/Access/AccessPolicy.cs
@@ -14,6 +14,7 @@ public static class AccessPolicy
Capability.InvitePeople
or Capability.CreateProductsAndTeams
or Capability.ConfigureAgents
+ or Capability.ManageSkills
or Capability.SetAutonomy
or Capability.ApproveHeldActions
or Capability.WorkTasks
diff --git a/src/Shared/TeamUp.SharedKernel/Access/Capability.cs b/src/Shared/TeamUp.SharedKernel/Access/Capability.cs
index 3ee62e3..d6abe84 100644
--- a/src/Shared/TeamUp.SharedKernel/Access/Capability.cs
+++ b/src/Shared/TeamUp.SharedKernel/Access/Capability.cs
@@ -11,6 +11,7 @@ public enum Capability
InvitePeople,
CreateProductsAndTeams,
ConfigureAgents,
+ ManageSkills,
SetAutonomy,
ApproveHeldActions,
WorkTasks,
diff --git a/tests/TeamUp.IntegrationTests/AnyRoleSeatTests.cs b/tests/TeamUp.IntegrationTests/AnyRoleSeatTests.cs
index 380ece0..e5894a3 100644
--- a/tests/TeamUp.IntegrationTests/AnyRoleSeatTests.cs
+++ b/tests/TeamUp.IntegrationTests/AnyRoleSeatTests.cs
@@ -122,6 +122,7 @@ public sealed class AnyRoleSeatTests(PostgresFixture postgres) : IClassFixture(client, "/api/orgboard/teams", new { organizationId = owner.OrganizationId, name = "IPNOPS" });
diff --git a/tests/TeamUp.IntegrationTests/ReviewFlowTests.cs b/tests/TeamUp.IntegrationTests/ReviewFlowTests.cs
index 671da79..5992497 100644
--- a/tests/TeamUp.IntegrationTests/ReviewFlowTests.cs
+++ b/tests/TeamUp.IntegrationTests/ReviewFlowTests.cs
@@ -236,6 +236,7 @@ public sealed class ReviewFlowTests(PostgresFixture postgres) : IClassFixture
+/// The dynamic per-company skill library: an org authors a skill, versions it, and forks a builtin —
+/// all org-scoped (own + shared builtins visible, gated by ManageSkills), with the publish gate intact.
+///
+public sealed class SkillLibraryTests(PostgresFixture postgres) : IClassFixture
+{
+ private const string BuiltinSkill =
+ """
+ ---
+ id: spec-writing
+ name: Spec Writing
+ version: 1.0.0
+ summary: Turn a request into a spec.
+ roles: [product-owner]
+ actions:
+ - name: write-spec
+ risk: draft
+ golden_tests:
+ - input: "Add a logout button"
+ expected: "A logout button in the header that ends the session."
+ ---
+ # Spec Writing
+ Write a clear, testable spec.
+ """;
+
+ private sealed record BootstrapResponse(string Token, Guid MemberId, Guid OrganizationId);
+
+ private sealed record AuthResponse(string Token, Guid MemberId);
+
+ private sealed record InviteResponse(Guid InvitationId, string Token);
+
+ private sealed record ActionDto(string Name, string Risk, string? Description);
+
+ private sealed record GoldenTestDto(string Input, string Expected);
+
+ private sealed record SkillSummary(
+ string SkillKey, string Name, string Version, string? Summary, List Roles,
+ string Visibility, string MinTier, string Status, string Origin, Guid? OrganizationId,
+ int GoldenTestCount, List Actions);
+
+ private sealed record SkillDetail(
+ SkillSummary Skill, string? Inputs, string? Outputs, List Tools,
+ List Context, List GoldenTests, string Body);
+
+ [Fact]
+ public async Task Org_authors_versions_and_forks_skills_scoped_to_itself()
+ {
+ await using var factory = new TeamUpWebFactory(postgres.ConnectionString);
+ using var anon = factory.CreateClient();
+
+ var owner = await PostOk(anon, "/api/identity/bootstrap", new
+ {
+ organizationName = "AliaSaaS",
+ ownerEmail = "owner@alia.test",
+ ownerDisplayName = "Owner",
+ ownerPassword = "Passw0rd!",
+ });
+ using var client = Authed(factory, owner.Token);
+ client.DefaultRequestHeaders.Add("X-Skills-Admin-Key", TeamUpWebFactory.PlatformAdminKey);
+
+ // A builtin exists in the shared (null-org) namespace.
+ await PostOk(client, "/api/skills/index", new { content = BuiltinSkill });
+
+ // The org authors its own skill. Roles + a golden test → Published.
+ var authored = await PostOk(client, "/api/skills/authored", new
+ {
+ organizationId = owner.OrganizationId,
+ skillKey = "api-design",
+ name = "API Design",
+ version = "1.0.0",
+ summary = "Design an endpoint.",
+ roles = new[] { "engineer" },
+ inputs = "A story.",
+ outputs = "Route + shapes.",
+ actions = new[] { new { name = "write-design", risk = "draft", description = "Emit a design." } },
+ tools = Array.Empty(),
+ context = Array.Empty(),
+ visibility = "private",
+ minTier = "free",
+ body = "You are the engineer. Design the endpoint.",
+ goldenTests = new[] { new { input = "Delete own comment", expected = "DELETE /comments/{id} 204/403/404" } },
+ });
+ Assert.Equal("Published", authored.Skill.Status);
+ Assert.Equal("Authored", authored.Skill.Origin);
+ Assert.Equal(owner.OrganizationId, authored.Skill.OrganizationId);
+
+ // Bump the version → a new row; both coexist.
+ await PostOk(client, "/api/skills/authored", new
+ {
+ organizationId = owner.OrganizationId,
+ skillKey = "api-design",
+ name = "API Design",
+ version = "1.1.0",
+ summary = "Design an endpoint (v2).",
+ roles = new[] { "engineer" },
+ inputs = (string?)null,
+ outputs = (string?)null,
+ actions = Array.Empty