Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
# ADR-001: Initial Design of the Agent Knowledge Layer (AKL)

## Status

Proposed

## Context

Gemini CLI agents lack persistent, high-level situational awareness across
long-running workstreams (Epics/Features) and tend to repeat mistakes (loops) or
lose track of established patterns. Current hierarchical memory (`GEMINI.md`) is
rarely updated by agents.

## Decision

We will implement an "Agent Knowledge Layer" (AKL) that provides:

1. **Multi-Layered Storage:**
- `machine-learnings.md` at Global, Project, and Micro levels for patterns
and optimizations.
- `.gemini/epics/<id>/` for situational awareness tied to branches/issues.
2. **GitHub-Aware Discovery:** Syncing context from GitHub issues (including
parent issues) at session start.
3. **Active Synthesis:** Tools for agents to record ADRs (`record_decision`),
update Epic state (`update_epic_state`), and record learnings
(`record_learning`).
4. **Experimental Gating:** Feature flag `experimental.akl`.

## Consequences

- **Pros:** Improved consistency across complex task loops, reduced repetition
of failure patterns, clear documentation of architectural decisions.
- **Cons:** Slight overhead at session start for discovery; potential for
context pollution if not indexed effectively.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
!.gemini/config.yaml
!.gemini/commands/
!.gemini/skills/
!.gemini/epics/
!.gemini/settings.json

# Note: .gemini-clipboard/ is NOT in gitignore so Gemini can access pasted images
Expand Down
1 change: 1 addition & 0 deletions docs/cli/settings.md
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,7 @@ they appear in the UI.
| Use OSC 52 Paste | `experimental.useOSC52Paste` | Use OSC 52 for pasting. This may be more robust than the default system when using remote terminal sessions (if your terminal is configured to allow it). | `false` |
| Use OSC 52 Copy | `experimental.useOSC52Copy` | Use OSC 52 for copying. This may be more robust than the default system when using remote terminal sessions (if your terminal is configured to allow it). | `false` |
| Plan | `experimental.plan` | Enable Plan Mode. | `true` |
| Agent Knowledge Layer | `experimental.akl` | Enable the Agent Knowledge Layer for persistent situational awareness. | `false` |
| Model Steering | `experimental.modelSteering` | Enable model steering (user hints) to guide the model during tool execution. | `false` |
| Direct Web Fetch | `experimental.directWebFetch` | Enable web fetch behavior that bypasses LLM summarization. | `false` |
| Topic & Update Narration | `experimental.topicUpdateNarration` | Enable the experimental Topic & Update communication model for reduced chattiness and structured progress reporting. | `false` |
Expand Down
6 changes: 6 additions & 0 deletions docs/reference/configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -1215,6 +1215,12 @@ their corresponding top-level category object in your `settings.json` file.
- **Default:** `false`
- **Requires restart:** Yes

- **`experimental.akl`** (boolean):
- **Description:** Enable the Agent Knowledge Layer for persistent situational
awareness.
- **Default:** `false`
- **Requires restart:** Yes

- **`experimental.modelSteering`** (boolean):
- **Description:** Enable model steering (user hints) to guide the model
during tool execution.
Expand Down
27 changes: 1 addition & 26 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 6 additions & 0 deletions packages/cli/src/config/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,7 @@ export interface CliArgs {
includeDirectories: string[] | undefined;
screenReader: boolean | undefined;
useWriteTodos: boolean | undefined;
akl: boolean | undefined;
outputFormat: string | undefined;
fakeResponses: string | undefined;
recordResponses: string | undefined;
Expand Down Expand Up @@ -272,6 +273,10 @@ export async function parseArguments(
type: 'boolean',
description: 'Enable screen reader mode for accessibility.',
})
.option('akl', {
type: 'boolean',
description: 'Enable the Agent Knowledge Layer (AKL).',
})
.option('output-format', {
alias: 'o',
type: 'string',
Expand Down Expand Up @@ -835,6 +840,7 @@ export async function loadCliConfig(
truncateToolOutputThreshold: settings.tools?.truncateToolOutputThreshold,
eventEmitter: coreEvents,
useWriteTodos: argv.useWriteTodos ?? settings.useWriteTodos,
akl: argv.akl ?? settings.experimental?.akl,
output: {
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
format: (argv.outputFormat ?? settings.output?.format) as OutputFormat,
Expand Down
17 changes: 10 additions & 7 deletions packages/cli/src/config/extension-manager-themes.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,11 @@ describe('ExtensionManager theme loading', () => {

// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
const mockConfig = {
getAklEnabled: () => false,
getImportFormat: () => 'tree' as const,
getFileFilteringOptions: () => ({}),
getDiscoveryMaxDirs: () => 200,
getAklFilePaths: async () => [],
getEnableExtensionReloading: () => false,
getMcpClientManager: () => ({
startExtension: vi.fn().mockResolvedValue(undefined),
Expand Down Expand Up @@ -140,7 +145,6 @@ describe('ExtensionManager theme loading', () => {
getExtensions: () => [],
}),
isTrustedFolder: () => true,
getImportFormat: () => 'tree',
reloadSkills: vi.fn(),
} as unknown as Config;

Expand Down Expand Up @@ -192,13 +196,12 @@ describe('ExtensionManager theme loading', () => {
getExtensionLoader: () => ({
getExtensions: () => [],
}),
isTrustedFolder: () => true,
getImportFormat: () => 'tree',
getFileFilteringOptions: () => ({
respectGitIgnore: true,
respectGeminiIgnore: true,
}),
getAklEnabled: () => false,
getAklFilePaths: async () => [],
getImportFormat: () => 'tree' as const,
getFileFilteringOptions: () => ({}),
getDiscoveryMaxDirs: () => 200,
isTrustedFolder: () => true,
getMcpClientManager: () => ({
getMcpInstructions: () => '',
startExtension: vi.fn().mockResolvedValue(undefined),
Expand Down
10 changes: 10 additions & 0 deletions packages/cli/src/config/settingsSchema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1936,6 +1936,16 @@ const SETTINGS_SCHEMA = {
description: 'Enable task tracker tools.',
showInDialog: false,
},
akl: {
type: 'boolean',
label: 'Agent Knowledge Layer',
category: 'Experimental',
requiresRestart: true,
default: false,
description:
'Enable the Agent Knowledge Layer for persistent situational awareness.',
showInDialog: true,
},
modelSteering: {
type: 'boolean',
label: 'Model Steering',
Expand Down
6 changes: 4 additions & 2 deletions packages/cli/src/gemini.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -499,15 +499,17 @@ describe('gemini.tsx main function kitty protocol', () => {
allowedMcpServerNames: undefined,
allowedTools: undefined,
experimentalAcp: undefined,
acp: undefined,
extensions: undefined,
listExtensions: undefined,
resume: undefined,
includeDirectories: undefined,
screenReader: undefined,
useWriteTodos: undefined,
resume: undefined,
akl: undefined,
outputFormat: undefined,
listSessions: undefined,
deleteSession: undefined,
outputFormat: undefined,
fakeResponses: undefined,
recordResponses: undefined,
rawOutput: undefined,
Expand Down
9 changes: 6 additions & 3 deletions packages/cli/src/test-utils/mockConfig.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ import {
* Creates a mocked Config object with default values and allows overrides.
*/
export const createMockConfig = (overrides: Partial<Config> = {}): Config =>
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
({
getSandbox: vi.fn(() => undefined),
getQuestion: vi.fn(() => ''),
Expand Down Expand Up @@ -170,6 +169,12 @@ export const createMockConfig = (overrides: Partial<Config> = {}): Config =>
getBlockedMcpServers: vi.fn().mockReturnValue([]),
getExperiments: vi.fn().mockReturnValue(undefined),
getHasAccessToPreviewModel: vi.fn().mockReturnValue(false),
getAklEnabled: vi.fn().mockReturnValue(false),
getAklDiscoveryService: vi.fn().mockReturnValue({}),
getActiveEpicId: vi.fn().mockReturnValue(undefined),
setActiveEpicId: vi.fn(),
getImportFormat: vi.fn().mockReturnValue('tree'),
getDiscoveryMaxDirs: vi.fn().mockReturnValue(200),
validatePathAccess: vi.fn().mockReturnValue(null),
getUseAlternateBuffer: vi.fn().mockReturnValue(false),
...overrides,
Expand All @@ -182,11 +187,9 @@ export function createMockSettings(
overrides: Record<string, unknown> = {},
): LoadedSettings {
const merged = createTestMergedSettings(
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
(overrides['merged'] as Partial<Settings>) || {},
);

// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
return {
system: { settings: {} },
systemDefaults: { settings: {} },
Expand Down
Loading
Loading