Skip to content

Where people and agents ship software together. The open-source git platform for the whole job: issues, agents, checks and deploys to the edge.

102 linesCodeBlameRaw
1import { Brain } from "lucide-react";
2import { Link } from "react-router";
3
4import type { Route } from "./+types/memory";
5import { page } from "../../lib/meta";
6import { AddMemory, MemoryList, memoryAction } from "../../components/memory";
7import { agents } from "../../lib/services.server";
8import { assertSameOrigin, requireUser, roleIn, unwrap } from "../../lib/session.server";
9import { requireRepo } from "../../lib/access.server";
10
11export function meta({ params, ...args }: Route.MetaArgs) {
12 return page(args, { title: `Memory · ${params.owner}/${params.repo} · g1t` });
13}
14
15export async function loader({ params, context }: Route.LoaderArgs) {
16 // The project's memory is for anyone who can read the repository; the
17 // workspace's for its members only.
18 const { viewer, access } = await requireRepo(context, params, "read");
19 const member = !!roleIn(viewer, params.owner);
20 const path = { namespace: params.owner, name: params.repo };
21 const memories = await agents.listMemories(viewer, params.owner, path);
22 return {
23 ...unwrap(memories),
24 member,
25 // Adding to, editing and forgetting the project's memory: Write and up.
26 editable: access.can.push,
27 };
28}
29
30export async function action({ params, context, request }: Route.ActionArgs) {
31 assertSameOrigin(request);
32 const user = requireUser(context, request);
33 const form = await request.formData();
34 return memoryAction(agents, user, params.owner, { namespace: params.owner, name: params.repo }, form);
35}
36
37export default function ProjectMemory({ loaderData, params }: Route.ComponentProps) {
38 const { project, workspace, member, editable } = loaderData;
39 const action = `/${params.owner}/${params.repo}/memory`;
40 return (
41 <div className="max-w-4xl">
42 <h2 className="flex items-center gap-2 text-xl font-semibold tracking-tight">
43 <Brain size={19} className="text-accent" />
44 Memory
45 </h2>
46 <p className="mt-1.5 max-w-2xl text-sm text-muted">
47 What people and coding agents have saved about this project that the next agent should know: how
48 to build and test it, its conventions, decisions and why, and its traps. Agents read it with
49 the MCP server's recall, pinned first{member ? ", together with the workspace's memory" : ""}, and add to it with
50 remember{editable ? "; keep it true by editing or forgetting what no longer holds" : ""}.
51 </p>
52 {!editable && (
53 <p className="mt-2 text-xs text-muted">
54 You can read this project's memory. Adding to it and changing it needs the Write role.
55 </p>
56 )}
57
58 {editable && (
59 <div className="mt-6">
60 <AddMemory scope="project" action={action} placeholder="The tests need TZ=UTC or the date tests fail." />
61 </div>
62 )}
63
64 <section className="mt-8">
65 <div className="flex items-baseline justify-between">
66 <h3 className="text-sm font-medium">This project</h3>
67 <span className="text-xs text-muted">{project.length} kept</span>
68 </div>
69 <div className="mt-3">
70 <MemoryList
71 memories={project}
72 action={action}
73 editable={editable}
74 empty={editable ? "Nothing yet. Agents add to it with remember, and so can you." : "Nothing yet."}
75 />
76 </div>
77 </section>
78
79 {member && (
80 <section className="mt-10">
81 <div className="flex items-baseline justify-between">
82 <h3 className="text-sm font-medium">From the workspace</h3>
83 <Link to={`/${params.owner}/-/memory`} className="text-xs text-muted hover:text-fg">
84 Manage workspace memory
85 </Link>
86 </div>
87 <p className="mt-1 text-xs text-muted">
88 True across all of {params.owner}'s projects, and recalled here too.
89 </p>
90 <div className="mt-3">
91 <MemoryList
92 memories={workspace}
93 action={`/${params.owner}/-/memory`}
94 editable={false}
95 empty="The workspace remembers nothing yet."
96 />
97 </div>
98 </section>
99 )}
100 </div>
101 );
102}