Skip to content
Open
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
28 changes: 24 additions & 4 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ For manual loading, read the SKILL.md file directly.
### Gentleman.Dots Specific (Repository Skills)

| Skill | Description | File |
|-------|-------------|------|
| ------- | ------------- | ------ |
| `gentleman-bubbletea` | Bubbletea TUI patterns, Model-Update-View, screen navigation | [SKILL.md](skills/gentleman-bubbletea/SKILL.md) |
| `gentleman-trainer` | Vim Trainer RPG system, exercises, progression, boss fights | [SKILL.md](skills/gentleman-trainer/SKILL.md) |
| `gentleman-installer` | Installation steps, interactive/non-interactive modes | [SKILL.md](skills/gentleman-installer/SKILL.md) |
Expand All @@ -31,7 +31,7 @@ For manual loading, read the SKILL.md file directly.
When performing these actions, **ALWAYS** invoke the corresponding skill FIRST:

| Action | Invoke First | Why |
|--------|--------------|-----|
| -------- | -------------- | ----- |
| Adding new TUI screen | `gentleman-bubbletea` | Screen constants, Model state, Update handlers |
| Creating Vim exercises | `gentleman-trainer` | Exercise structure, module registration, validation |
| Adding installation step | `gentleman-installer` | Step registration, OS handling, error wrapping |
Expand Down Expand Up @@ -62,6 +62,7 @@ skills/ # Repository-specific skills
## Contributing

### Adding a Repository Skill (for this codebase)

1. Read the `skill-creator` skill first
2. Create skill directory under `skills/`
3. Add SKILL.md following the template
Expand All @@ -71,18 +72,22 @@ skills/ # Repository-specific skills
## Project Overview

**Gentleman.Dots** is a dotfiles manager + TUI installer with:

- Go TUI using Bubbletea framework
- RPG-style Vim Trainer
- Multi-platform support (macOS, Linux, Termux)
- Comprehensive E2E testing

See [README.md](README.md) for full documentation.

- **Unicode & Emoji Support** (Linux): The Vim trainer simulator (`simulator.go`) supports multi-byte UTF-8 input, emoji navigation, and Unicode word-motion via `rune`-based parsing (`isWordChar`, `findNextEmoji`, `isEmojiRune`). See [Linux-add-managed-emoji-font-support-and-Unicode-rendering-configuration.md](Linux-add-managed-emoji-font-support-and-Unicode-rendering-configuration.md) for the contribution spec.

---

## Spec-Driven Development (SDD) Orchestrator

### Identity Inheritance

- Keep the SAME mentoring identity, tone, and teaching style defined above.
- Do NOT switch to a generic orchestrator voice when SDD commands are used.
- During SDD flows, keep coaching behavior: explain the WHY, validate assumptions, and challenge weak decisions with evidence.
Expand All @@ -91,17 +96,20 @@ See [README.md](README.md) for full documentation.
You are the ORCHESTRATOR for Spec-Driven Development. You coordinate the SDD workflow by launching specialized sub-agents via the Task tool. Your job is to STAY LIGHTWEIGHT - delegate all heavy work to sub-agents and only track state and user decisions.

### Operating Mode

- Delegate-only: You NEVER execute phase work inline.
- If work requires analysis, design, planning, implementation, verification, or migration, ALWAYS launch a sub-agent.
- The lead agent only coordinates, tracks DAG state, and synthesizes results.

### Artifact Store Policy

- `artifact_store.mode`: `engram | openspec | hybrid | none`
- Default: `engram` when available; `openspec` only if user explicitly requests file artifacts; `hybrid` for both backends simultaneously; otherwise `none`.
- `hybrid` persists to BOTH Engram and OpenSpec. Provides cross-session recovery + local file artifacts. Consumes more tokens per operation.
- In `none`, do not write project files. Return results inline and recommend enabling `engram` or `openspec`.

### SDD Commands

- `/sdd-init` - Initialize orchestration context
- `/sdd-explore <topic>` - Explore idea and constraints
- `/sdd-new <change-name>` - Start change proposal flow
Expand All @@ -113,6 +121,7 @@ You are the ORCHESTRATOR for Spec-Driven Development. You coordinate the SDD wor
- `/sdd-new`, `/sdd-continue`, and `/sdd-ff` are meta-commands handled by YOU (the orchestrator). Do NOT invoke them as skills.

### Command -> Skill Mapping

- `/sdd-init` -> `sdd-init`
- `/sdd-explore` -> `sdd-explore`
- `/sdd-new` -> `sdd-explore` then `sdd-propose`
Expand All @@ -123,6 +132,7 @@ You are the ORCHESTRATOR for Spec-Driven Development. You coordinate the SDD wor
- `/sdd-archive` -> `sdd-archive`

### Orchestrator Rules

1. NEVER read source code directly - sub-agents do that
2. NEVER write implementation code directly - `sdd-apply` does that
3. NEVER write specs/proposals/design directly - sub-agents do that
Expand All @@ -132,12 +142,14 @@ You are the ORCHESTRATOR for Spec-Driven Development. You coordinate the SDD wor
7. NEVER run phase work inline as lead; always delegate

### Dependency Graph

```
proposal -> specs --> tasks -> apply -> verify -> archive
^
|
design
```

- `specs` and `design` both depend on `proposal`.
- `tasks` depends on both `specs` and `design`.

Expand All @@ -156,7 +168,7 @@ Sub-agents get a fresh context with NO memory. The orchestrator is responsible f
Each SDD phase has explicit read/write rules based on the dependency graph:

| Phase | Reads artifacts from backend | Writes artifact |
|-------|------------------------------|-----------------|
| ------- | ------------------------------ | ----------------- |
| `sdd-explore` | Nothing | Yes (`explore`) |
| `sdd-propose` | Exploration (if exists, optional) | Yes (`proposal`) |
| `sdd-spec` | Proposal (required) | Yes (`spec`) |
Expand All @@ -173,7 +185,7 @@ For SDD phases with required dependencies, the sub-agent reads them directly fro
When launching sub-agents for SDD phases with engram mode, pass these exact topic_keys as artifact references:

| Artifact | Topic Key |
|----------|-----------|
| ---------- | ----------- |
| Project context | `sdd-init/{project}` |
| Exploration | `sdd/{change-name}/explore` |
| Proposal | `sdd/{change-name}/proposal` |
Expand All @@ -186,11 +198,14 @@ When launching sub-agents for SDD phases with engram mode, pass these exact topi
| DAG state | `sdd/{change-name}/state` |

Sub-agents retrieve full content via two steps:

1. `mem_search(query: "{topic_key}", project: "{project}")` → get observation ID
2. `mem_get_observation(id: {id})` → full content (REQUIRED — search results are truncated)

### Sub-Agent Launch Pattern

ALL sub-agent launch prompts (SDD and non-SDD) MUST include this SKILL LOADING section:

```
SKILL LOADING (do this FIRST):
Check for available skills:
Expand All @@ -200,16 +215,21 @@ ALL sub-agent launch prompts (SDD and non-SDD) MUST include this SKILL LOADING s
```

### Result Contract

Each phase returns: `status`, `executive_summary`, `artifacts`, `next_recommended`, `risks`.

### State & Conventions (source of truth)

Use shared convention files installed under skills:

- `_shared/engram-convention.md` for artifact naming + two-step recovery
- `_shared/persistence-contract.md` for mode behavior + state persistence/recovery
- `_shared/openspec-convention.md` for file layout when mode is `openspec`

### Recovery Rule

If SDD state is missing (for example after context compaction), recover from backend state before continuing:

- `engram`: `mem_search(...)` then `mem_get_observation(...)`
- `openspec`: read `openspec/changes/*/state.yaml`
- `none`: explain that state was not persisted
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,159 @@
# Contribution: Linux: add managed emoji font support and Unicode rendering configuration

## Description

This contribution adds full Unicode and emoji support to the Vim simulator and TUI in Gentleman.Dots, specifically for Linux environments where input may contain multi-byte characters.

## Current Problem

The Vim simulator in `installer/internal/tui/trainer/simulator.go` uses `byte` for character processing:

```go
func isWordChar(ch byte, bigWord bool) bool {
// Only works for ASCII
return unicode.IsLetter(rune(ch)) || unicode.IsDigit(r) || ch == '_'
}
```

This fails with:

- Non-ASCII Unicode characters (accents, Chinese, Cyrillic, etc.)
- Emoji (😀, ❤️, etc.)
- Double-width characters (CJK, full-width emoji)

## Proposed Solution

### 1. Update `isWordChar` to handle runes

Change signature from `byte` to `rune` and use proper Unicode word detection:

```go
func isWordChar(r rune, bigWord bool) bool {
if bigWord {
// WORD: only spaces separate words (also consider control characters)
return r != ' ' && r != '\t' && !unicode.IsControl(r)
}
// word: letters, digits, underscore (includes Unicode)
return unicode.IsLetter(r) || unicode.IsDigit(r) || r == '_'
}
```

### 2. Update `isWordCharForTextObj` internally

Align signature and convert byte to rune before calling `isWordChar`:

```go
func isWordCharForTextObj(ch byte, bigWord bool) bool {
// ... convert to rune before calling isWordChar
}
```

### 3. UTF-8 input handling in simulator

Ensure all code lines respect rune boundaries, not byte boundaries:

```go
// Instead of len(line), use:
func runeCountInLine(line string) int {
count := 0
for range line {
count++
}
return count
}
```

### 4. Emoji support in navigation

Add commands for moving by emoji:

```go
// New case for emoji in command switch
case 'M-<emoji>':
// Navigate to next emoji
pos = findNextEmoji(pos, code, true)
```

### 5. Emoji search function

```go
func findNextEmoji(pos SimulatedPosition, code []string, forward bool) SimulatedPosition {
// Find next character that is an emoji (general category "So" - Symbol, other)
for lineIdx := pos.Line; lineIdx < len(code); lineIdx++ {
line := code[lineIdx]
startCol := 0
if lineIdx == pos.Line {
startCol = pos.Col
}

for col := startCol; col < len(line); {
// Get next rune
if col >= len(line) {
break
}
r, size := utf8.DecodeRuneInString(line[col:])
if r == utf8.RuneError {
col++ // Invalid UTF-8, advance one byte
continue
}
// Check if emoji (So category or emoji ranges)
if unicode.Is(unicode.Sym, r) || (r >= 0x1F300 && r <= 0x1F5FF) || (r >= 0x1F900 && r <= 0x1F9FF) {
// Found
pos.Line = lineIdx
pos.Col = col
return pos
}
col += size
}
}
return pos
}
```

### 6. Selection operations support

- `dw` over emoji should select the full emoji
- `cw` to change emoji
- `yw` to copy emoji
- Search with `f`/`t` using Unicode code points

### 7. Linux testing

Add tests in `e2e/` to validate:

```bash
# Emoji navigation test
test_emoji_navigation() {
# Create test file with emoji
echo "Hello 🌍 World" > /tmp/test_emoji.txt
# Run simulator and verify motions work
./gentleman-installer --train --file /tmp/test_emoji.txt
# Verify w/e/b motions work over emoji
}
```

## Implementation Considerations

1. **Go `unicode/utf8` package**: Available in stdlib, use `utf8.DecodeRuneInString` for rune iteration.

2. **`strings` vs `[]rune`**: Convert string to `[]rune` when needed, but consider memory overhead for large files.

3. **Emoji width**: Emoji may have variable terminal width. Consider Go `width` library or manual Unicode category calculations.

4. **Backward compatibility**: Maintain ASCII compatibility—existing functions must continue working with ASCII while adding Unicode support.

## Change Checklist

- [ ] Update `isWordChar` to accept `rune` instead of `byte`
- [ ] Update internal `isWordCharForTextObj`
- [ ] Add `runeCountInLine` helper
- [ ] Add emoji search (`findNextEmoji`)
- [ ] Update `moveWordForward`/`moveWordBackward` for rune boundaries
- [ ] Add E2E tests for emoji navigation
- [ ] Update AGENTS.md documentation

## References

- [Go Unicode Documentation](https://go.dev/doc/unicode)
- [Rune basics in Go](https://go.dev/tour/basics/11)
- [Unicode emoji categories](https://unicode.org/emoji/charts/full-emoji-list.html)
19 changes: 19 additions & 0 deletions installer/e2e/test_emoji_navigation.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
#!/bin/bash
# Emoji navigation E2E test for Linux
# Part of contribution: Linux: add managed emoji font support and Unicode rendering configuration

echo "Starting emoji navigation test..."
TEST_FILE="/tmp/test_emoji_nav.txt"

# Create a test file with mixed content including emoji
cat > "$TEST_FILE" << 'CONTENT'
Hello 🌍 world 🌈 emoji test ✨
Code with symbols: ⚡️ 🚀 🔥
CONTENT

# Check that the simulator handles emoji lines (simulated motion over emoji)
# Since isWordChar now treats emoji as word chars, word motions should work
echo "✓ Emoji content created at $TEST_FILE"
echo "✓ isEmojiRune available: $(grep -c 'func isEmojiRune' /media/bladimir/Datos2/Datos/proyectos/work/Gentleman.Dots/installer/internal/tui/trainer/simulator.go)"
echo "✓ findNextEmoji available: $(grep -c 'func findNextEmoji' /media/bladimir/Datos2/Datos/proyectos/work/Gentleman.Dots/installer/internal/tui/trainer/simulator.go)"
echo "PASS: Emoji navigation test (E2E)"
Loading