Use bundled project agents template

This commit is contained in:
2026-06-02 10:59:16 +02:00
parent e3f4e87319
commit 3aed1c8f92
2 changed files with 19 additions and 35 deletions
@@ -260,6 +260,19 @@ public sealed class WorkflowRulesEditorTests
Assert.Equal("Direct project instructions.", await File.ReadAllTextAsync(Path.Combine(betaRoot, "AGENTS.md"))); Assert.Equal("Direct project instructions.", await File.ReadAllTextAsync(Path.Combine(betaRoot, "AGENTS.md")));
Assert.False(File.Exists(Path.Combine(betaRoot, "PROJECT.md"))); Assert.False(File.Exists(Path.Combine(betaRoot, "PROJECT.md")));
Assert.StartsWith("Refused:", await tools.CreateProject("../Escape")); Assert.StartsWith("Refused:", await tools.CreateProject("../Escape"));
var missingTemplateTools = new WorkflowRulesEditorTools(
new MeetingAssistantOptions
{
Vault =
{
ProjectsFolder = projectsRoot
}
},
projectAgentsTemplatePath: Path.Combine(root, "Missing-Project-AGENTS.md"));
var missingTemplate = await missingTemplateTools.CreateProject("Gamma Project");
Assert.StartsWith("Refused: recommended project AGENTS.md template was not found:", missingTemplate);
Assert.False(Directory.Exists(Path.Combine(projectsRoot, "Gamma Project")));
} }
[Fact] [Fact]
@@ -368,6 +368,11 @@ public sealed class WorkflowRulesEditorTools
return "Refused: agents_md seed requires AGENTS.md content."; return "Refused: agents_md seed requires AGENTS.md content.";
} }
if (normalizedSeed == "recommended" && !File.Exists(projectAgentsTemplatePath))
{
return $"Refused: recommended project AGENTS.md template was not found: {projectAgentsTemplatePath}.";
}
Directory.CreateDirectory(projectRoot.Path!); Directory.CreateDirectory(projectRoot.Path!);
switch (normalizedSeed) switch (normalizedSeed)
{ {
@@ -940,9 +945,7 @@ public sealed class WorkflowRulesEditorTools
private async Task WriteRecommendedProjectSeedAsync(string projectRoot, string projectName) private async Task WriteRecommendedProjectSeedAsync(string projectRoot, string projectName)
{ {
var agentsContent = File.Exists(projectAgentsTemplatePath) var agentsContent = await File.ReadAllTextAsync(projectAgentsTemplatePath);
? await File.ReadAllTextAsync(projectAgentsTemplatePath)
: DefaultProjectAgentsContent;
await File.WriteAllTextAsync(Path.Combine(projectRoot, "AGENTS.md"), agentsContent); await File.WriteAllTextAsync(Path.Combine(projectRoot, "AGENTS.md"), agentsContent);
await File.WriteAllTextAsync(Path.Combine(projectRoot, "PROJECT.md"), CreateDefaultProjectFile(projectName)); await File.WriteAllTextAsync(Path.Combine(projectRoot, "PROJECT.md"), CreateDefaultProjectFile(projectName));
await File.WriteAllTextAsync(Path.Combine(projectRoot, "JOURNAL.md"), CreateDefaultJournalFile(projectName)); await File.WriteAllTextAsync(Path.Combine(projectRoot, "JOURNAL.md"), CreateDefaultJournalFile(projectName));
@@ -999,38 +1002,6 @@ public sealed class WorkflowRulesEditorTools
"""; """;
} }
private const string DefaultProjectAgentsContent = """
The project is split in 3 important files:
PROJECT.md
DECISIONS.md
JOURNAL.md
The idea is a hierarchical summary:
Meeting Summary -> detailed (what was discussed)
then Journal Entry -> compressed (why should I care this event happened?)
then PROJECT.md -> distilled (what do I absolutely have to know about this project EVERY TIME I work on it. This is an onboarding document that every agent should read.)
The journal should always be appended and read using tail or searched.
Journal entries use this shape:
```markdown
## 2026-05-30
### Team Daily
New Blocker: HLS delayed
Impact: Release likely delayed, team implements Z-Levels in the meantime.
[[20260529-093030-6187486-summary|Summary]]
```
DECISIONS.md logs only important decisions in a compressed way, with a link to ADRs and/or meeting summaries for details.
Important decisions are architecture decisions that are expensive to change, or project decisions about timeline, goals, governance, team, or process.
Do not log small implementation details such as how UI elements are aligned.
""";
private async Task<MeetingArtifactSummary> ReadMeetingArtifactSummaryAsync(string path) private async Task<MeetingArtifactSummary> ReadMeetingArtifactSummaryAsync(string path)
{ {
var content = await File.ReadAllTextAsync(path); var content = await File.ReadAllTextAsync(path);