Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
103 commits
Select commit Hold shift + click to select a range
ca554f1
chk: knot-1
DIodide Feb 26, 2026
7662e6c
significantly better
DIodide Feb 26, 2026
07652e2
to indigo
DIodide Feb 26, 2026
ed34360
pre commit hook change
DIodide Feb 26, 2026
1702f5a
change to black
DIodide Feb 26, 2026
4567ed0
add shadcn-ui components from default registry
DIodide Feb 26, 2026
6ca6267
add logo
DIodide Feb 26, 2026
d087562
add sign-in page
DIodide Feb 26, 2026
b18d060
implement TanStack Router authentication guards and remove deprecated…
DIodide Feb 26, 2026
be1fe34
format __root with biome
DIodide Feb 26, 2026
de27980
Add the convex backend path to the tsconfig to include it during lin…
DIodide Feb 26, 2026
9b70d6e
add convex-backend as a dep to the web project + add markdown renderi…
DIodide Feb 26, 2026
ebf1e40
add proper chat page
DIodide Feb 26, 2026
3692db1
biome format
DIodide Feb 26, 2026
fbedbdc
style change
DIodide Feb 26, 2026
64babeb
use best practice for convex id typing
DIodide Feb 26, 2026
ce12102
seed the floating dots to not break SSR
DIodide Feb 27, 2026
2b8fc0f
add composite index by_user_last_message to support recency filtering
DIodide Feb 27, 2026
d95313e
Change list harnesses query to use this recency by last message mutation
DIodide Feb 27, 2026
02c04d1
remove double model_config definition
DIodide Feb 27, 2026
8401dc8
decouple harnesses from conversations, keep track of last harness use…
DIodide Feb 27, 2026
8f32744
Add settings + sign out feature + signout ui
DIodide Feb 27, 2026
4ef2340
Merge pull request #3 from DIodide/feat/landing-page
DIodide Feb 27, 2026
5c6b704
Merge pull request #4 from DIodide/feat/login-and-onboarding
DIodide Feb 27, 2026
22c8bd9
initial chat-implementation
DIodide Feb 27, 2026
f597e54
biome format
DIodide Feb 27, 2026
18675f7
delete packages/backend
DIodide Feb 27, 2026
1ba5874
test
richardw19 Feb 27, 2026
c1ea761
add missing dep
jon3350 Feb 27, 2026
1412864
add proper error handling and fastapi Depends or retrieving http clie…
DIodide Feb 28, 2026
14ec96b
Add logging to MCP errors and tool calls 2
DIodide Feb 28, 2026
5f81ca6
add logging for openrouter
DIodide Feb 28, 2026
c19a657
add logging for auth
DIodide Feb 28, 2026
756ca94
Add logging to main
DIodide Feb 28, 2026
abd3039
Add environment and config validation + logging to FastAPI
DIodide Feb 28, 2026
d88e906
add manage profile option to user settings
DIodide Mar 1, 2026
5763178
formatting
DIodide Mar 1, 2026
ec662f4
Enhance chat streaming functionality by introducing per-conversation …
DIodide Mar 1, 2026
0c02062
add loading spinner on streaming chats
DIodide Mar 1, 2026
7862cec
format
DIodide Mar 1, 2026
d26096c
Add animation for chat completion
DIodide Mar 1, 2026
df15fb7
format
DIodide Mar 1, 2026
26c7e26
Update packages/fastapi/app/config.py
DIodide Mar 1, 2026
2936d25
Update packages/fastapi/app/auth.py
DIodide Mar 1, 2026
db62032
add reasoning support
DIodide Mar 1, 2026
a41f4d3
basic tool calls working + dynamic httpstreamable mcps
DIodide Mar 1, 2026
21cf316
persist tool call output and render to screen
DIodide Mar 1, 2026
e406f47
add QoL modes for interactivity
DIodide Mar 1, 2026
6363077
add usage token data, costs, to the developer mode ui
DIodide Mar 1, 2026
3f4dfb4
add include usage to openrouter
DIodide Mar 1, 2026
13087d5
parallelize tool calls
DIodide Mar 1, 2026
4d67fbc
stream tool calls correctly.
DIodide Mar 1, 2026
7cf478b
log openrouter error: set max_tokens: 4096 for non thinking models an…
DIodide Mar 1, 2026
883ae74
working parts stream + persist, + fix conversations css
DIodide Mar 2, 2026
f6727be
Add backend oauth implementation + routes based on MCP standard
DIodide Mar 2, 2026
06e3240
add frontend handling for oauth connectivity + initial ui
DIodide Mar 2, 2026
be0bd76
Add chat interrupts, auto scroll
DIodide Mar 4, 2026
c97104a
Merge pull request #6 from DIodide:feat/chat-interrupts-and-scroll
DIodide Mar 4, 2026
73a24b4
Merge pull request #5 from DIodide/feat/initial-chat+oauth-implementa…
DIodide Mar 4, 2026
1c1ed1e
Merge branch 'staging' into feat/mcp-implementation
DIodide Mar 4, 2026
e287513
Update apps/web/src/routes/harnesses/index.tsx
DIodide Mar 4, 2026
98b9b35
remove migrations.ts
DIodide Mar 4, 2026
1bb307e
Merge branch 'feat/mcp-implementation' of https://github.com/DIodide/…
DIodide Mar 4, 2026
f92956a
remove migrations
DIodide Mar 4, 2026
85d351c
sign in ui
DIodide Mar 4, 2026
af9df03
default to newly created harness (prefer)
DIodide Mar 4, 2026
398bdac
add in-onboarding auth step
DIodide Mar 4, 2026
3aaccfe
use t3-oss-env validator instead of meta.env
DIodide Mar 4, 2026
ba3aa24
add mcp server status check in the ui
DIodide Mar 4, 2026
81f5685
show mcp error on frontend
DIodide Mar 4, 2026
5db47ac
add ui indicator for api/mcp/health/check
DIodide Mar 4, 2026
0901548
ease connectivity for mcp servers that do not support sessions
DIodide Mar 4, 2026
6ca2e28
indicator
DIodide Mar 5, 2026
a033b4c
linear support + proxies
DIodide Mar 6, 2026
e5dbaed
fix auto scroll issue
DIodide Mar 6, 2026
1f4eaa9
add gpt-5.4
DIodide Mar 7, 2026
38e1c34
Merge pull request #7 from DIodide/feat/mcp-implementation
DIodide Mar 9, 2026
03a66cc
lower max tokens
DIodide Mar 9, 2026
dfc92fe
Added inital UI and MCP interfaces and list refactor
cole-ramer Mar 10, 2026
f876ea9
small changes
cole-ramer Mar 10, 2026
4c162bb
Changed PresetMcpDefintion, and created onboarding selector with ever…
cole-ramer Mar 10, 2026
fb2d310
Finishing old commit?
cole-ramer Mar 10, 2026
a9af39d
Logic and Ui for selectable MCPs, just missing icons and actual selec…
cole-ramer Mar 11, 2026
d78f3d3
Presets working with icons and descriptions. Slack doesn't work until…
cole-ramer Mar 11, 2026
8998474
updated format
cole-ramer Mar 11, 2026
2579d38
Duplicate harnesses
cole-ramer Mar 11, 2026
2ae2ff0
feat: added fork conversation and edit prompt functionalities
richardw19 Mar 13, 2026
0d86e59
Added search bar in chatsidebar to search for keywords in title and m…
jon3350 Mar 15, 2026
21fcb1a
minor change. see last commit message
jon3350 Mar 15, 2026
da4a0f9
Added show more/show less feature when searching. Uses usePaginatedQu…
jon3350 Mar 16, 2026
8ea9c7c
Delete Arch md file
cole-ramer Mar 18, 2026
ee6c7e6
fixed bug where show more button appears when inital number of querie…
jon3350 Mar 18, 2026
4ad5506
added fork banner when forking a conversation. Clicking directs you b…
richardw19 Mar 18, 2026
c964819
added url validation to the onbaroding and harness creation page. The…
jon3350 Mar 18, 2026
6d1a2fd
Merge main into staging (GitHub Actions workflows)
DIodide Mar 18, 2026
a9c11bd
fixed comments from pull request. Conversations uses take instead of …
jon3350 Mar 18, 2026
d27cb19
minor fix, see last comment
jon3350 Mar 18, 2026
c547723
re-implemented editPrompt functionality. Added pagenation for differe…
richardw19 Mar 18, 2026
e54bea5
bug fixes
cole-ramer Mar 18, 2026
a9f7d34
Merge pull request #15 from DIodide/feat/fork_and_edit
DIodide Mar 18, 2026
7449e82
Merge staging into feat/chat-search, resolving conflict in chat/index…
DIodide Mar 18, 2026
4586c98
Merge pull request #12 from DIodide/feat/chat-search
DIodide Mar 18, 2026
9347bc6
Merge pull request #11 from DIodide/feat/selectable-mcps-to-staging
DIodide Mar 18, 2026
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
68 changes: 68 additions & 0 deletions .cursor/rules/convex-id-types.mdc
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
---
description: Use Convex branded Id types instead of plain strings for document IDs. Applies when working with Convex state, props, or mutations.
globs: apps/web/src/**/*.tsx,apps/web/src/**/*.ts,packages/convex-backend/convex/**/*.ts
alwaysApply: false
---

# Convex Branded ID Types

## Rule

NEVER use `string` for Convex document IDs. NEVER use `as never` or `as Id<"...">` casts to silence type mismatches. Instead, use the generated `Id<"tablename">` type from `@harness/convex-backend/convex/_generated/dataModel` throughout the entire type chain — state, props, callbacks, and function parameters.

## Why

Convex generates branded types like `Id<"harnesses">` that are distinct from `string` at the type level. This prevents accidentally passing an `Id<"harnesses">` where an `Id<"conversations">` is expected. Using `as never` completely defeats this safety.

## Import

```tsx
import type { Id } from "@harness/convex-backend/convex/_generated/dataModel";
```

## Pattern: State

```tsx
// GOOD — proper branded type
const [activeId, setActiveId] = useState<Id<"harnesses"> | null>(null);

// BAD — plain string loses type safety
const [activeId, setActiveId] = useState<string | null>(null);
```

## Pattern: Component Props

```tsx
// GOOD — types flow from Convex queries to mutations without casts
function HarnessCard({
harness,
onDelete,
}: {
harness: { _id: Id<"harnesses">; name: string };
onDelete: (id: Id<"harnesses">) => void;
}) {
return <button onClick={() => onDelete(harness._id)}>Delete</button>;
}
```

## Pattern: Mutations

```tsx
// GOOD — types match, no casts needed
const removeHarness = useMutation({
mutationFn: useConvexMutation(api.harnesses.remove),
});
removeHarness.mutate({ id: harness._id }); // Id<"harnesses"> flows naturally

// BAD — as never bypasses ALL type checking
removeHarness.mutate({ id: someString as never });
```

## How It Works

1. Convex query results already return `_id` as `Id<"tablename">`
2. Store these in state with `useState<Id<"tablename"> | null>`
3. Pass through props with `Id<"tablename">` (not `string`)
4. When the value reaches a mutation call, types match — zero casts needed

The key is to never widen `Id<"tablename">` to `string` at any point in the chain.
95 changes: 95 additions & 0 deletions .cursor/rules/tanstack-auth-guards.mdc
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
---
description: Use TanStack Router beforeLoad guards for authentication instead of navigating during render. Applies when creating or modifying protected routes in this project.
globs: apps/web/src/routes/**/*.tsx
alwaysApply: false
---

# TanStack Router + Clerk Auth Guards

## Rule

NEVER call `navigate()` during the render phase for authentication redirects. This is a React anti-pattern that causes unpredictable behavior, especially with SSR (TanStack Start).

Instead, use TanStack Router's `beforeLoad` option to check authentication and `throw redirect()` before the component ever mounts.

## How it works in this project

The root route (`__root.tsx`) already fetches Clerk auth state server-side and injects `userId` into the route context:

```tsx
// __root.tsx — beforeLoad returns { userId, token } into context
beforeLoad: async (ctx) => {
const { userId, token } = await fetchClerkAuth();
if (token) {
ctx.context.convexQueryClient.serverHttpClient?.setAuth(token);
}
return { userId, token };
},
```

Child routes access `context.userId` in their own `beforeLoad`.

## Pattern: Protected Route

```tsx
import { createFileRoute, redirect } from "@tanstack/react-router";

export const Route = createFileRoute("/my-protected-route")({
beforeLoad: ({ context }) => {
if (!context.userId) {
throw redirect({ to: "/sign-in" });
}
},
component: MyProtectedPage,
});

function MyProtectedPage() {
// No need for useUser() auth checks here — the user is guaranteed
// to be authenticated by the time this component renders.
}
```

## Anti-pattern (DO NOT use)

```tsx
// BAD — navigating during render
function MyPage() {
const { user } = useUser();
const navigate = useNavigate();

if (!user) {
navigate({ to: "/sign-in" }); // Side effect during render!
return null;
}
}
```

## Data-dependent redirects

For redirects that depend on client-side data (e.g., Convex queries), use `useEffect` — not a bare call during render:

```tsx
function ChatPage() {
const navigate = useNavigate();
const { data: harnesses, isLoading } = useQuery(convexQuery(api.harnesses.list, {}));

useEffect(() => {
if (harnesses && harnesses.length === 0) {
navigate({ to: "/onboarding" });
}
}, [harnesses, navigate]);

if (isLoading || !harnesses || harnesses.length === 0) {
return <LoadingSkeleton />;
}

// ... rest of component
}
```

## Key points

- `beforeLoad` runs top-down through the route tree, before any child `beforeLoad` or component.
- `throw redirect()` accepts the same options as `navigate()` (e.g., `replace: true`, `search: {}`).
- If `beforeLoad` throws, child routes will not load at all.
- Do NOT import `useUser` from Clerk just for auth checks in route components — use `context.userId` in `beforeLoad` instead.
3 changes: 3 additions & 0 deletions apps/web/.env.example
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,6 @@ CLERK_SECRET_KEY=sk_test_

# Convex configuration, get this URL from your [Dashboard](dashboard.convex.dev)
VITE_CONVEX_URL=https://your-project.convex.cloud

# FastAPI backend URL
VITE_FASTAPI_URL=http://localhost:8000
5 changes: 4 additions & 1 deletion apps/web/biome.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,10 @@
"linter": {
"enabled": true,
"rules": {
"recommended": true
"recommended": true,
"correctness": {
"useUniqueElementIds": "off"
}
}
},
"javascript": {
Expand Down
10 changes: 9 additions & 1 deletion apps/web/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,9 @@
"dependencies": {
"@clerk/tanstack-react-start": "^0.29.1",
"@convex-dev/react-query": "^0.1.0",
"@harness/convex-backend": "workspace:*",
"@t3-oss/env-core": "^0.13.8",
"@tailwindcss/typography": "^0.5.19",
"@tailwindcss/vite": "^4.1.18",
"@tanstack/react-devtools": "^0.7.0",
"@tanstack/react-query": "^5.90.21",
Expand All @@ -27,15 +29,21 @@
"class-variance-authority": "^0.7.1",
"clsx": "^2.1.1",
"convex": "^1.31.7",
"geist": "^1.7.0",
"highlight.js": "^11.11.1",
"lucide-react": "^0.561.0",
"nitro": "npm:nitro-nightly@latest",
"motion": "^12.34.3",
"radix-ui": "^1.4.3",
"react": "^19.2.0",
"react-dom": "^19.2.0",
"react-hot-toast": "^2.6.0",
"react-markdown": "^10.1.0",
"rehype-highlight": "^7.0.2",
"remark-gfm": "^4.0.1",
"tailwind-merge": "^3.0.2",
"tailwindcss": "^4.1.18",
"tw-animate-css": "^1.3.6",
"use-sync-external-store": "^1.6.0",
"vite-tsconfig-paths": "^6.0.2",
"zod": "^4.1.11"
},
Expand Down
9 changes: 9 additions & 0 deletions apps/web/public/favicon.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added apps/web/public/fonts/Geist-Variable.woff2
Binary file not shown.
Binary file added apps/web/public/fonts/GeistMono-Variable.woff2
Binary file not shown.
79 changes: 0 additions & 79 deletions apps/web/src/components/Header.tsx

This file was deleted.

26 changes: 26 additions & 0 deletions apps/web/src/components/harness-mark.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
export function HarnessMark({
size = 24,
className,
}: {
size?: number;
className?: string;
}) {
return (
<svg
width={size}
height={size}
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
strokeLinecap="round"
strokeLinejoin="round"
className={className}
aria-hidden="true"
>
<path d="M7 4v16" strokeWidth="2.5" />
<path d="M17 4v16" strokeWidth="2.5" />
<path d="M7 12 C9.5 8, 14.5 8, 17 12" strokeWidth="2" />
<path d="M7 12 C9.5 16, 14.5 16, 17 12" strokeWidth="2" />
</svg>
);
}
Loading
Loading