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
2 changes: 1 addition & 1 deletion AGENTS.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Everything Claude Code (ECC) — Agent Instructions

This is a **production-ready AI coding plugin** providing 25 specialized agents, 108 skills, 57 commands, and automated hook workflows for software development.
This is a **production-ready AI coding plugin** providing 25 specialized agents, 109 skills, 57 commands, and automated hook workflows for software development.

## Core Principles

Expand Down
5 changes: 3 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -191,7 +191,7 @@ For manual install instructions see the README in the `rules/` folder.
/plugin list everything-claude-code@everything-claude-code
```

✨ **That's it!** You now have access to 25 agents, 108 skills, and 57 commands.
✨ **That's it!** You now have access to 25 agents, 109 skills, and 57 commands.

---

Expand Down Expand Up @@ -289,6 +289,7 @@ everything-claude-code/
| |-- videodb/ # Video and audio: ingest, search, edit, generate, stream (NEW)
| |-- golang-patterns/ # Go idioms and best practices
| |-- golang-testing/ # Go testing patterns, TDD, benchmarks
| |-- harper-best-practices/ # Harper schema, APIs, authentication, deployment
| |-- cpp-coding-standards/ # C++ coding standards from C++ Core Guidelines (NEW)
| |-- cpp-testing/ # C++ testing with GoogleTest, CMake/CTest (NEW)
| |-- django-patterns/ # Django patterns, models, views (NEW)
Expand Down Expand Up @@ -1044,7 +1045,7 @@ The configuration is automatically detected from `.opencode/opencode.json`.
|---------|-------------|----------|--------|
| Agents | ✅ 25 agents | ✅ 12 agents | **Claude Code leads** |
| Commands | ✅ 57 commands | ✅ 31 commands | **Claude Code leads** |
| Skills | ✅ 108 skills | ✅ 37 skills | **Claude Code leads** |
| Skills | ✅ 109 skills | ✅ 37 skills | **Claude Code leads** |
| Hooks | ✅ 8 event types | ✅ 11 events | **OpenCode has more!** |
| Rules | ✅ 29 rules | ✅ 13 instructions | **Claude Code leads** |
| MCP Servers | ✅ 14 servers | ✅ Full | **Full parity** |
Expand Down
40 changes: 40 additions & 0 deletions rules/harper/adding-tables-with-schemas.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
---
name: adding-tables-with-schemas
description: Guidelines for adding tables to a Harper database using GraphQL schemas.
---

# Adding Tables with Schemas

Instructions for the agent to follow when adding tables to a Harper database.

## When to Use

Use this skill when you need to define new data structures or modify existing ones in a Harper database.

## How It Works

1. **Create Dedicated Schema Files**: Prefer having a dedicated schema `.graphql` file for each table. Check the `config.yaml` file under `graphqlSchema.files` to see how it's configured. It typically accepts wildcards (e.g., `schemas/*.graphql`), but may be configured to point at a single file.
2. **Use Directives**: All available directives for defining your schema are defined in `node_modules/harperdb/schema.graphql`. Common directives include `@table`, `@export`, `@primaryKey`, `@indexed`, and `@relationship`.
3. **Define Relationships**: Link tables together using the `@relationship` directive. For more details, see the [Defining Relationships](defining-relationships.md) skill.
4. **Enable Automatic APIs**: If you add `@table @export` to a schema type, Harper automatically sets up REST and WebSocket APIs for basic CRUD operations against that table. For a detailed list of available endpoints and how to use them, see the [Automatic REST APIs](automatic-apis.md) skill.
- `GET /{TableName}`: Describes the schema itself.
- `GET /{TableName}/`: Lists all records (supports filtering, sorting, and pagination via query parameters). See the [Querying REST APIs](querying-rest-apis.md) skill for details.
- `GET /{TableName}/{id}`: Retrieves a single record by its ID.
- `POST /{TableName}/`: Creates a new record.
- `PUT /{TableName}/{id}`: Updates an existing record.
- `PATCH /{TableName}/{id}`: Performs a partial update on a record.
- `DELETE /{TableName}/`: Deletes all records or filtered records.
- `DELETE /{TableName}/{id}`: Deletes a single record by its ID.
5. **Consider Table Extensions**: If you are going to [extend the table](./extending-tables.md) in your resources, then do not `@export` the table from the schema.

## Examples

In a hypothetical `schemas/ExamplePerson.graphql`:

```graphql
type ExamplePerson @table @export {
id: ID @primaryKey
name: String
tag: String @indexed
}
```
37 changes: 37 additions & 0 deletions rules/harper/automatic-apis.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
---
name: automatic-apis
description: How to use Harper's automatically generated REST and WebSocket APIs.
---

# Automatic APIs

Instructions for the agent to follow when utilizing Harper's automatic APIs.

## When to Use

Use this skill when you want to interact with Harper tables via REST or WebSockets without writing custom resource logic. This is ideal for basic CRUD operations and real-time updates.

## How It Works

1. **Enable Automatic APIs**: Ensure your GraphQL schema includes the `@export` directive for the table.
2. **Access REST Endpoints**: Use the standard endpoints for your table (Note: Paths are case-sensitive).
3. **Use Automatic WebSockets**: Connect to `wss://your-harper-instance/{TableName}` to receive events whenever updates are made to that table. This is the easiest way to add real-time capabilities. (Use `ws://` for local development without SSL). For more complex needs, see [Real-time Apps](real-time-apps.md).
4. **Apply Filtering and Querying**: Use query parameters with `GET /{TableName}/` and `DELETE /{TableName}/`. See the [Querying REST APIs](querying-rest-apis.md) skill for advanced details.
5. **Customize if Needed**: If the automatic APIs don't meet your requirements, [customize the resources](./custom-resources.md).

## Examples

### Schema Configuration

```graphql
type MyTable @table @export {
id: ID @primaryKey
name: String
}
```

### Common REST Operations

- **List Records**: `GET /MyTable/`
- **Create Record**: `POST /MyTable/`
- **Update Record**: `PATCH /MyTable/{id}`
50 changes: 50 additions & 0 deletions rules/harper/caching.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
---
name: caching
description: How to implement integrated data caching in Harper from external sources.
---

# Caching

Instructions for the agent to follow when implementing caching in Harper.

## When to Use

Use this skill when you need high-performance, low-latency storage for data from external sources. It's ideal for reducing API calls to third-party services, preventing cache stampedes, and making external data queryable as if it were native Harper tables.

## How It Works

1. **Configure a Cache Table**: Define a table in your `schema.graphql` with an `expiration` (in seconds).
2. **Define an External Source**: Create a Resource class that fetches the data from your source.
3. **Attach Source to Table**: Use `sourcedFrom` to link your resource to the table.
4. **Implement Active Caching (Optional)**: Use `subscribe()` for proactive updates. See [Real-Time Apps](real-time-apps.md).
5. **Implement Write-Through Caching (Optional)**: Define `put` or `post` in your resource to propagate updates upstream.

## Examples

### Schema Configuration

```graphql
type MyCache @table(expiration: 3600) @export {
id: ID @primaryKey
}
```

### Resource Implementation

```js
import { Resource, tables } from 'harperdb';

export class ThirdPartyAPI extends Resource {
async get() {
const id = this.getId();
const response = await fetch(`https://api.example.com/items/${id}`);
if (!response.ok) {
throw new Error('Source fetch failed');
}
return await response.json();
}
}

// Attach source to table
tables.MyCache.sourcedFrom(ThirdPartyAPI);
```
199 changes: 199 additions & 0 deletions rules/harper/checking-authentication.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,199 @@
---
name: checking-authentication
description: How to handle user authentication and sessions in Harper Resources.
---

# Checking Authentication

Instructions for the agent to follow when handling authentication and sessions.

## When to Use

Use this skill when you need to implement sign-in/sign-out functionality, protect specific resource endpoints, or identify the currently logged-in user in a Harper application.

## How It Works

1. **Configure Harper for Sessions**: Ensure `harperdb-config.yaml` has sessions enabled and local auto-authorization disabled for testing:
```yaml
authentication:
authorizeLocal: false
enableSessions: true
```
2. **Implement Sign In**: Use `this.getContext().login(username, password)` to create a session:
```typescript
async post(_target, data) {
const context = this.getContext();
try {
await context.login(data.username, data.password);
} catch {
return new Response('Invalid credentials', { status: 403 });
}
return new Response('Logged in', { status: 200 });
}
```
3. **Identify Current User**: Use `this.getCurrentUser()` to access session data:
```typescript
async get() {
const user = this.getCurrentUser?.();
if (!user) return new Response(null, { status: 401 });
Copy link
Contributor

@cubic-dev-ai cubic-dev-ai bot Mar 18, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2: GET /me example returns 401 for anonymous users, but the status-code conventions section specifies a 200 empty-body response for unauthenticated users, creating inconsistent guidance.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At rules/harper/checking-authentication.md, line 38:

<comment>`GET /me` example returns 401 for anonymous users, but the status-code conventions section specifies a 200 empty-body response for unauthenticated users, creating inconsistent guidance.</comment>

<file context>
@@ -0,0 +1,165 @@
+   ```ts
+   async get() {
+     const user = this.getCurrentUser?.();
+     if (!user) return new Response(null, { status: 401 });
+     return { username: user.username, role: user.role };
+   }
</file context>
Fix with Cubic

return { username: user.username, role: user.role };
}
```
4. **Implement Sign Out**: Use `this.getContext().logout()` or delete the session from context:
```typescript
async post() {
const context = this.getContext();
await context.session?.delete?.(context.session.id);
return new Response('Logged out', { status: 200 });
}
```
5. **Protect Routes**: In your Resource, use `allowRead()`, `allowUpdate()`, etc., to enforce authorization logic based on `this.getCurrentUser()`. For privileged actions, verify `user.role.permission.super_user`.

## Examples

### Sign In Implementation

```typescript
async post(_target, data) {
const context = this.getContext();
try {
await context.login(data.username, data.password);
} catch {
return new Response('Invalid credentials', { status: 403 });
}
return new Response('Logged in', { status: 200 });
}
```

### Identify Current User

```typescript
async get() {
const user = this.getCurrentUser?.();
if (!user) return new Response(null, { status: 401 });
return { username: user.username, role: user.role };
}
```

### Sign Out Implementation

```typescript
async post() {
const context = this.getContext();
await context.session?.delete?.(context.session.id);
return new Response('Logged out', { status: 200 });
}
```

## Status code conventions used here

- 200: Successful operation. For `GET /me`, a `200` with empty body means “not signed in”.
- 400: Missing required fields (e.g., username/password on sign-in).
- 401: No current session for an action that requires one (e.g., sign out when not signed in).
- 403: Authenticated but not authorized (bad credentials on login attempt, or insufficient privileges).

## Client considerations

- Sessions are cookie-based; the server handles setting and reading the cookie via Harper. If you make cross-origin requests, ensure the appropriate `credentials` mode and CORS settings.
- If developing locally, double-check the server config still has `authentication.authorizeLocal: false` to avoid accidental superuser bypass.

## Token-based auth (JWT + refresh token) for non-browser clients

Cookie-backed sessions are great for browser flows. For CLI tools, mobile apps, or other non-browser clients, it’s often easier to use **explicit tokens**:

- **JWT (`operation_token`)**: short-lived bearer token used to authorize API requests.
- **Refresh token (`refresh_token`)**: longer-lived token used to mint a new JWT when it expires.

This project includes two Resource patterns for that flow:

### Issuing tokens: `IssueTokens`

**Description / use case:** Generate `{ refreshToken, jwt }` either:

- with an existing Authorization token (either Basic Auth or a JWT) and you want to issue new tokens, or
- from an explicit `{ username, password }` payload (useful for direct “login” from a CLI/mobile client).

```javascript
export class IssueTokens extends Resource {
static loadAsInstance = false;

async get(target) {
const { refresh_token: refreshToken, operation_token: jwt } =
await databases.system.hdb_user.operation(
{ operation: 'create_authentication_tokens' },
this.getContext(),
);
return { refreshToken, jwt };
}

async post(target, data) {
if (!data.username || !data.password) {
throw new Error('username and password are required');
}

const { refresh_token: refreshToken, operation_token: jwt } =
await databases.system.hdb_user.operation({
operation: 'create_authentication_tokens',
username: data.username,
password: data.password,
});
return { refreshToken, jwt };
}
}
```
Comment on lines +116 to +143
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 databases and Resource used without imports

The IssueTokens and RefreshJWT code blocks (lines 117–143 and lines 158–173) use both databases.system.hdb_user.operation(...) and extends Resource without importing either. Resource is always explicitly imported from harperdb in the other rule files (e.g., custom-resources.md, extending-tables.md). It's unclear whether databases is a Harper runtime global like tables, or if it also needs to be imported. If it does need to be imported, any developer copying these snippets will get a ReferenceError at runtime.

If databases is a global, a brief inline comment would help clarify its origin. If not, the imports should be added at the top of each snippet, for example:

import { Resource, databases } from 'harperdb'; // if databases needs an import

The same pattern applies to the RefreshJWT example further down.


**Recommended documentation notes to include:**

- `GET` variant: intended for “I already have an Authorization token, give me new tokens”.
- `POST` variant: intended for “I have credentials, give me tokens”.
- Response shape:
- `refreshToken`: store securely (long-lived).
- `jwt`: attach to requests (short-lived).

### Refreshing a JWT: `RefreshJWT`

**Description / use case:** When the JWT expires, the client uses the refresh token to get a new JWT without re-supplying username/password.

```javascript
export class RefreshJWT extends Resource {
static loadAsInstance = false;

async post(target, data) {
if (!data.refreshToken) {
throw new Error('refreshToken is required');
}

const { operation_token: jwt } = await databases.system.hdb_user.operation({
operation: 'refresh_operation_token',
refresh_token: data.refreshToken,
});
return { jwt };
}
}
```

**Recommended documentation notes to include:**

- Requires `refreshToken` in the request body.
- Returns a new `{ jwt }`.
- If refresh fails (expired/revoked), client must re-authenticate (e.g., call `IssueTokens.post` again).

### Suggested client flow (high-level)

1. **Sign in (token flow)**
- POST /IssueTokens/ with a body of `{ "username": "your username", "password": "your password" }` or GET /IssueTokens/ with an existing Authorization token.
- Receive `{ jwt, refreshToken }` in the response
2. **Call protected APIs**
- Send the JWT with each request in the Authorization header (as your auth mechanism expects)
3. **JWT expires**
- POST /RefreshJWT/ with a body of `{ "refreshToken": "your refresh token" }`.
- Receive `{ jwt }` in the response and continue

## Quick checklist

- [ ] Public endpoints explicitly `allowRead`/`allowCreate` as needed.
- [ ] Sign-in uses `context.login` and handles 400/403 correctly.
- [ ] Protected routes call `ensureSuperUser(this.getCurrentUser())` (or another role check) before doing work.
- [ ] Sign-out verifies a session and deletes it.
- [ ] `authentication.authorizeLocal` is `false` and `enableSessions` is `true` in Harper config.
- [ ] If using tokens: `IssueTokens` issues `{ jwt, refreshToken }`, `RefreshJWT` refreshes `{ jwt }` with a `refreshToken`.
28 changes: 28 additions & 0 deletions rules/harper/creating-a-fabric-account-and-cluster.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
---
name: creating-a-fabric-account-and-cluster
description: How to create a Harper Fabric account, organization, and cluster.
---

# Creating a Harper Fabric Account and Cluster

Follow these steps to set up your Harper Fabric environment for deployment.

## How It Works

1. **Sign Up/In**: Go to [https://fabric.harper.fast/](https://fabric.harper.fast/) and sign up or sign in.
2. **Create an Organization**: Create an organization (org) to manage your projects.
3. **Create a Cluster**: Create a new cluster. This can be on the free tier, no credit card required.
4. **Set Credentials**: During setup, set the cluster username and password to finish configuring it.
5. **Get Application URL**: Navigate to the **Config** tab and copy the **Application URL**.
6. **Configure Environment**: Update your `.env` file or GitHub Actions secrets with cluster-specific credentials.
7. **Next Steps**: See the [deploying-to-harper-fabric](deploying-to-harper-fabric.md) rule for detailed instructions on deploying your application successfully.

## Examples

### Environment Configuration

```bash
CLI_TARGET_USERNAME='YOUR_CLUSTER_USERNAME'
CLI_TARGET_PASSWORD='YOUR_CLUSTER_PASSWORD'
CLI_TARGET='YOUR_CLUSTER_URL'
```
Loading