Skip to content

Commit f2aa5a2

Browse files
committed
init and update (Release v0.5.3)
1 parent 00ab398 commit f2aa5a2

File tree

12 files changed

+563
-126
lines changed

12 files changed

+563
-126
lines changed

README.md

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -197,7 +197,8 @@ The tinyMem CLI is your primary way to interact with the system from your termin
197197
| `run` | **Command Wrapper**| To run a script or tool (like `make` or `npm test`) while "reminding" it of project context. | `tinymem run make build` |
198198
| `proxy` / `mcp` | **Server Modes** | To start the "brain" that connects tinyMem to your IDE or AI client. | `tinymem mcp` |
199199
| `doctor` | **Diagnostics** | To fix the system if it stops working or has configuration issues. | `tinymem doctor` |
200-
| `addContract` | **Agent Setup** | To automatically configure your AI agents to use tinyMem properly. | `tinymem addContract` |
200+
| `init` | **Project Bootstrap** | Creates `.tinyMem`, writes the config, and installs the correct agent contracts for your model size. | `tinymem init` |
201+
| `update` | **Refresh** | Re-runs migrations and downloads whichever agent contract matches your configuration. | `tinymem update` |
201202

202203
### Writing Memories
203204
Think of writing memories as "tagging" reality for the AI.
@@ -298,12 +299,13 @@ When tinyMem is running in MCP mode, your AI agent (like Claude or Gemini) gains
298299
### AI Agent Directives
299300
**CRITICAL**: If you are building an AI agent, you MUST include the appropriate directive in its system prompt to ensure it uses tinyMem correctly.
300301

301-
**Quick Setup:** Run `tinymem addContract` to automatically create these files in your project.
302+
**Quick Setup:** Run `tinymem init` once to bootstrap `.tinyMem`, create config, and install the correct agent contract for your model size. Use `tinymem update` later to rerun migrations and refresh the contract (it will download the small or large version that your configuration points to).
302303

303304
* **Claude**: [`docs/agents/CLAUDE.md`](docs/agents/CLAUDE.md)
304305
* **Gemini**: [`docs/agents/GEMINI.md`](docs/agents/GEMINI.md)
305306
* **Qwen**: [`docs/agents/QWEN.md`](docs/agents/QWEN.md)
306-
* **Other**: [`docs/agents/AGENT_CONTRACT.md`](docs/agents/AGENT_CONTRACT.md)
307+
* **Other (Large LLMs)**: [`docs/agents/AGENT_CONTRACT.md`](docs/agents/AGENT_CONTRACT.md)
308+
* **Other (Tiny LLMs)**: [`docs/agents/AGENT_CONTRACT_SMALL.md`](docs/agents/AGENT_CONTRACT_SMALL.md)
307309

308310
---
309311

cmd/tinymem/main.go

Lines changed: 85 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package main
22

33
import (
4+
"bufio"
45
"context"
56
"fmt"
67
"net"
@@ -13,15 +14,17 @@ import (
1314

1415
"github.com/daverage/tinymem/internal/analytics"
1516
"github.com/daverage/tinymem/internal/app"
17+
"github.com/daverage/tinymem/internal/config"
1618
"github.com/daverage/tinymem/internal/cove"
19+
"github.com/daverage/tinymem/internal/memory"
20+
"github.com/daverage/tinymem/internal/storage"
1721
"github.com/spf13/cobra"
1822
"go.uber.org/zap"
1923

2024
"github.com/daverage/tinymem/internal/doctor"
2125
"github.com/daverage/tinymem/internal/evidence"
2226
"github.com/daverage/tinymem/internal/inject"
2327
"github.com/daverage/tinymem/internal/logging"
24-
"github.com/daverage/tinymem/internal/memory"
2528
"github.com/daverage/tinymem/internal/recall"
2629
"github.com/daverage/tinymem/internal/server/mcp"
2730
"github.com/daverage/tinymem/internal/server/proxy"
@@ -44,7 +47,8 @@ func init() {
4447
rootCmd.AddCommand(doctorCmd)
4548
rootCmd.AddCommand(recentCmd)
4649
rootCmd.AddCommand(queryCmd)
47-
rootCmd.AddCommand(contractCmd)
50+
rootCmd.AddCommand(initCmd)
51+
rootCmd.AddCommand(updateCmd)
4852
rootCmd.AddCommand(completionCmd)
4953
rootCmd.AddCommand(dashboardCmd)
5054
rootCmd.AddCommand(writeCmd)
@@ -591,16 +595,55 @@ func runWriteCmd(a *app.App, cmd *cobra.Command, args []string) {
591595
}
592596
}
593597

594-
var contractCmd = &cobra.Command{
595-
Use: "addContract",
596-
Short: "Add the MANDATORY TINYMEM CONTROL PROTOCOL to agent markdown files",
598+
var initCmd = &cobra.Command{
599+
Use: "init",
600+
Short: "Initialize tinyMem state (config, database, contract files)",
601+
}
602+
603+
var updateCmd = &cobra.Command{
604+
Use: "update",
605+
Short: "Update database schema and refresh agent contracts",
606+
}
607+
608+
func runInitCmd(a *app.App, cmd *cobra.Command, args []string) {
609+
projectRoot := a.Project.Path
610+
fmt.Printf("Initializing tinyMem in %s\n", projectRoot)
611+
612+
defaultContract := memory.ParseContractType(a.Core.Config.AgentContract)
613+
contractType := selectContractType(defaultContract)
614+
615+
if err := config.SaveAgentContractChoice(projectRoot, string(contractType)); err != nil {
616+
a.Core.Logger.Error("Failed to persist agent contract choice", zap.Error(err))
617+
fmt.Printf("❌ Unable to save agent contract choice: %v\n", err)
618+
os.Exit(1)
619+
}
620+
a.Core.Config.AgentContract = string(contractType)
621+
622+
if err := memory.EnsureProjectContracts(projectRoot, contractType); err != nil {
623+
a.Core.Logger.Error("Failed to initialize agent contracts", zap.Error(err))
624+
fmt.Printf("❌ Contract initialization failed: %v\n", err)
625+
os.Exit(1)
626+
}
627+
628+
fmt.Println("tinyMem initialization complete.")
597629
}
598630

599-
func runContractCmd(a *app.App, cmd *cobra.Command, args []string) {
600-
if err := memory.AddContract(); err != nil {
601-
a.Core.Logger.Error("Failed to add contract", zap.Error(err))
602-
fmt.Printf("❌ Failed to add contract: %v\n", err)
631+
func runUpdateCmd(a *app.App, cmd *cobra.Command, args []string) {
632+
fmt.Println("Running database migrations and refreshing contracts...")
633+
if err := runMigrations(a.Core.Config); err != nil {
634+
a.Core.Logger.Error("Failed to run migrations", zap.Error(err))
635+
fmt.Printf("❌ Migration failed: %v\n", err)
636+
os.Exit(1)
637+
}
638+
639+
contractType := memory.ParseContractType(a.Core.Config.AgentContract)
640+
if err := memory.EnsureProjectContracts(a.Project.Path, contractType); err != nil {
641+
a.Core.Logger.Error("Failed to refresh contracts", zap.Error(err))
642+
fmt.Printf("❌ Contract refresh failed: %v\n", err)
643+
os.Exit(1)
603644
}
645+
646+
fmt.Println("Update complete.")
604647
}
605648

606649
var dashboardCmd = &cobra.Command{
@@ -659,6 +702,37 @@ func newAppRunner(a *app.App, runFunc func(*app.App, *cobra.Command, []string))
659702
}
660703
}
661704

705+
func runMigrations(cfg *config.Config) error {
706+
db, err := storage.NewDB(cfg)
707+
if err != nil {
708+
return err
709+
}
710+
return db.Close()
711+
}
712+
713+
func selectContractType(defaultType memory.ContractType) memory.ContractType {
714+
reader := bufio.NewReader(os.Stdin)
715+
fmt.Println("Which kind of LLM agent are you configuring?")
716+
fmt.Println(" small - Claude CLI, Ollama, Qwen3 8B (tiny, instruction-tuned models)")
717+
fmt.Println(" large - Claude 3, GPT-4.1 Turbo, Claude 3 Opus (default for bigger agents)")
718+
fmt.Printf("Choose contract (small/large) [%s]: ", defaultType)
719+
720+
input, err := reader.ReadString('\n')
721+
if err != nil {
722+
fmt.Printf("\nInput error, defaulting to %s\n", defaultType)
723+
return defaultType
724+
}
725+
726+
input = strings.TrimSpace(input)
727+
if input == "" {
728+
return defaultType
729+
}
730+
731+
selection := memory.ParseContractType(input)
732+
fmt.Printf("Selected %s agent contract\n", selection)
733+
return selection
734+
}
735+
662736
func main() {
663737
appInstance, err := app.NewApp()
664738
if err != nil {
@@ -681,7 +755,8 @@ func main() {
681755
doctorCmd.Run = newAppRunner(appInstance, runDoctorCmd)
682756
recentCmd.Run = newAppRunner(appInstance, runRecentCmd)
683757
queryCmd.Run = newAppRunner(appInstance, runQueryCmd)
684-
contractCmd.Run = newAppRunner(appInstance, runContractCmd)
758+
initCmd.Run = newAppRunner(appInstance, runInitCmd)
759+
updateCmd.Run = newAppRunner(appInstance, runUpdateCmd)
685760
dashboardCmd.Run = newAppRunner(appInstance, runDashboardCmd)
686761
writeCmd.Run = newAppRunner(appInstance, runWriteCmd)
687762

Lines changed: 128 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,128 @@
1+
**Start of tinyMem Protocol**
2+
# TINYMEM AGENT LAW (Tiny-LLM Edition)
3+
4+
This contract is **mandatory**.
5+
Responses that violate it are **invalid**.
6+
7+
---
8+
9+
## 1. Core Law
10+
11+
**No memory recall → no valid response.**
12+
13+
Memory recall is required on **every repository-related turn**, even if the result is empty.
14+
Tool usage is not optional when required by this law.
15+
16+
---
17+
18+
## 2. Mandatory Recall
19+
20+
The first action of every repository-related turn MUST be a memory recall tool call.
21+
22+
1. Call `memory_query` or `memory_recent`
23+
2. Acknowledge the result (even if zero entries)
24+
25+
If recall did not occur, STOP.
26+
27+
You may not infer memory.
28+
You may not pretend recall happened.
29+
30+
---
31+
32+
## 3. Task Authority
33+
34+
If `tinyTasks.md` exists:
35+
36+
* Unchecked tasks = you MUST continue the first unchecked subtask
37+
* No unchecked tasks = STOP and ask the user
38+
39+
You may NOT invent, skip, reorder, or redefine tasks.
40+
41+
If the file does not exist, state that explicitly.
42+
43+
You may not assume the existence or absence of tinyTasks.md. If uncertain, state uncertainty and STOP.
44+
45+
---
46+
47+
## 4. Mutation Requires Intent
48+
49+
You may NOT change durable state unless intent is declared.
50+
51+
Durable state includes:
52+
53+
* Writing files
54+
* Updating tasks
55+
* Writing memory
56+
57+
Mutation sequence (order is mandatory):
58+
59+
1. Recall memory
60+
2. Declare intent (`memory_set_mode`)
61+
3. Confirm task authority
62+
63+
---
64+
65+
## 5. Memory Writes (Tool-Only)
66+
67+
You may ONLY write memory using `memory_write`.
68+
69+
You may NEVER claim a memory was written unless the tool ran successfully.
70+
71+
Facts require evidence.
72+
Decisions and constraints require rationale.
73+
74+
If no memory write is needed, say so explicitly.
75+
76+
---
77+
78+
## 6. Prohibited Behavior
79+
80+
The following are forbidden and invalidate the response:
81+
82+
* Proceeding without memory recall
83+
* Claiming memory writes without tools
84+
* Ignoring existing tasks
85+
* Asking clarifying questions when a task exists
86+
* Resetting or redefining the task
87+
* Guessing state instead of checking
88+
89+
---
90+
91+
## 7. Failure Rule
92+
93+
If you are blocked by missing recall, task authority, or intent:
94+
95+
**STOP. STATE THE BLOCK. DO NOTHING ELSE.**
96+
97+
---
98+
99+
## 8. Output Discipline
100+
101+
* Do not explain this contract
102+
* Do not restate rules
103+
* Do not improvise authority
104+
* Do not optimize the process
105+
106+
Follow the law or stop.
107+
108+
---
109+
110+
**End of Agent Law**
111+
112+
---
113+
114+
## Why this works for tiny LLMs
115+
116+
Here’s the key design logic, so you know this isn’t guesswork:
117+
118+
* **Flat rules** no modes, no “recommended”
119+
* **Binary gates** do or stop
120+
* **No self-judgement** only checks
121+
* **Short enough** to stay in context
122+
* **Mirrors enforcement** the proxy can actually apply
123+
124+
Tiny models don’t need nuance.
125+
They need rails.
126+
127+
---
128+
**End of tinyMem Protocol**

examples/Aider.md

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ Aider needs to be told to talk to `localhost:8080` instead of the real API.
3535
aider \
3636
--openai-api-base http://localhost:8080/v1 \
3737
--openai-api-key dummy \
38-
--model openai/qwen2.5-coder # Prefix 'openai/' tells Aider to use generic client
38+
--model openai/rnj-1 # Prefix 'openai/' tells Aider to use generic client
3939
```
4040

4141
> **Critical:** You MUST use the `openai/` prefix for the model name (e.g., `openai/qwen2.5-coder` or `openai/gpt-4`). This forces Aider to use its generic OpenAI client, which respects the custom API base. If you just say `--model gpt-4`, it might try to hit the official OpenAI API directly.
@@ -79,4 +79,3 @@ aider --model-metadata-file .aider.model.metadata.json --model openai/qwen2.5-co
7979
- Ensure `tinymem proxy` is running.
8080
- Check `tinymem doctor`.
8181
- Try using `127.0.0.1` instead of `localhost` if on Windows/WSL.
82-

0 commit comments

Comments
 (0)