completion-kit 0.5.29 → 0.5.30
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 1bc6277357aee1869602b6c290d958c794788d14efc01d0c4caf1529d3567d69
|
|
4
|
+
data.tar.gz: a1e60f9278e2bc42c4e1bb487e850f7568a3b134b46e8dbc6b6b3d0bea79c469
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: fb4ffbbdb89589e0eca37f995ebc342bd6a6063160ca00cffa25abc956532a2b34aa7e6ce7b7c852802bcf5ed74cc4c49cb7f817ab36dbe07608bf18dd52dc1d
|
|
7
|
+
data.tar.gz: 61ef079b27c73bb749778e182052ac9c1e6824f1d432635210b647f716f10c5364f6ff8ec9b45cbc274d00b3d93d58b37613c61953596fd7ccf6fe89df1b88f0
|
data/README.md
CHANGED
|
@@ -18,19 +18,19 @@ It's the difference between "this prompt seems to work" and "this prompt scores
|
|
|
18
18
|
|
|
19
19
|
> **Just want to use it?** [CompletionKit Cloud](https://completionkit.com) is the same engine, fully hosted — zero install, no Rails ops, plans at [completionkit.com/pricing](https://completionkit.com/pricing).
|
|
20
20
|
|
|
21
|
-

|
|
22
22
|
|
|
23
23
|
## Three ways to run it
|
|
24
24
|
|
|
25
|
-
Same engine, same UI, same REST API and MCP server — pick the deployment that fits.
|
|
25
|
+
Same engine, same UI, same REST API and MCP server — pick the deployment that fits. The first two are stack-agnostic: you run CompletionKit as a product and talk to it over HTTP and MCP, whatever language your own app is written in. The third is for teams already building on Rails.
|
|
26
26
|
|
|
27
27
|
### 1. Hosted — [completionkit.com](https://completionkit.com) (recommended)
|
|
28
28
|
|
|
29
29
|
The fastest path. Sign up and you're running on the same engine you'd self-host, without touching a Rails app. No `db:migrate`, no Puma, no Solid Queue, no provider key management — multi-tenant workspaces, your team logs in, you go. Plans at [completionkit.com/pricing](https://completionkit.com/pricing).
|
|
30
30
|
|
|
31
|
-
### 2. Self-hosted — the bundled standalone
|
|
31
|
+
### 2. Self-hosted — the bundled standalone app
|
|
32
32
|
|
|
33
|
-
Run it on your own infra.
|
|
33
|
+
Run it on your own infra as a self-contained product. There's nothing to integrate and no Ruby to write — once it's up, you drive everything through the web UI, the REST API, and the MCP server, from whatever stack your own app is built in. It needs Postgres and a host that can run the app (Fly, Render, Heroku, Docker, …).
|
|
34
34
|
|
|
35
35
|
```bash
|
|
36
36
|
git clone https://github.com/homemade-software-inc/completion-kit.git
|
|
@@ -147,6 +147,12 @@ Limiting uses `Rails.cache`. A shared cache store (Solid Cache, Redis) throttles
|
|
|
147
147
|
|
|
148
148
|
## How it works
|
|
149
149
|
|
|
150
|
+
<p align="center">
|
|
151
|
+
<img src="https://raw.githubusercontent.com/homemade-software-inc/completion-kit/main/docs/diagrams/workflow.png" alt="CompletionKit workflow: a prompt and a dataset feed a run against a model, an LLM judge scores each output on your rubric, low scores drive an AI-suggested rewrite, and the new prompt version re-runs so you can compare" width="820" />
|
|
152
|
+
</p>
|
|
153
|
+
|
|
154
|
+
It's a loop. Each pass leaves you with a score you can compare against the last one.
|
|
155
|
+
|
|
150
156
|
1. **Create a prompt** with `{{variable}}` placeholders
|
|
151
157
|
2. **Upload a dataset.** A CSV where column headers match the variable names.
|
|
152
158
|
3. **Run it** against a model and score outputs with an LLM judge against criteria you define.
|
|
@@ -217,6 +223,37 @@ bin/rails db:migrate
|
|
|
217
223
|
git add db/migrate/ && git commit -m "install new engine migration"
|
|
218
224
|
```
|
|
219
225
|
|
|
226
|
+
### Docker
|
|
227
|
+
|
|
228
|
+
The standalone app ships a `Dockerfile`, so you can self-host it without a Ruby toolchain on the host. Build with the **repository root** as the context — the app depends on the engine source alongside it:
|
|
229
|
+
|
|
230
|
+
```bash
|
|
231
|
+
docker build -f standalone/Dockerfile -t completion-kit .
|
|
232
|
+
```
|
|
233
|
+
|
|
234
|
+
CompletionKit needs a Rails secret (`SECRET_KEY_BASE`) and three Active Record encryption keys. With Docker there's no Rails toolchain on the host to run `bin/rails db:encryption:init`, so generate them with `openssl`. Generate them **once** and keep them stable — if the encryption keys change, provider credentials already stored in the database can no longer be decrypted. Write everything to an env file:
|
|
235
|
+
|
|
236
|
+
```bash
|
|
237
|
+
cat > completion-kit.env <<EOF
|
|
238
|
+
DATABASE_URL=postgres://user:pass@host/completionkit
|
|
239
|
+
SECRET_KEY_BASE=$(openssl rand -hex 64)
|
|
240
|
+
COMPLETION_KIT_ENCRYPTION_PRIMARY_KEY=$(openssl rand -hex 32)
|
|
241
|
+
COMPLETION_KIT_ENCRYPTION_DETERMINISTIC_KEY=$(openssl rand -hex 32)
|
|
242
|
+
COMPLETION_KIT_ENCRYPTION_KEY_DERIVATION_SALT=$(openssl rand -hex 32)
|
|
243
|
+
EOF
|
|
244
|
+
```
|
|
245
|
+
|
|
246
|
+
`openssl rand` runs as the file is written, so each line gets a real random value. Keep `completion-kit.env` out of version control and back it up somewhere safe.
|
|
247
|
+
|
|
248
|
+
Run the web process and a job worker from the same image, both pointed at that file:
|
|
249
|
+
|
|
250
|
+
```bash
|
|
251
|
+
docker run -d -p 3000:3000 --env-file completion-kit.env completion-kit
|
|
252
|
+
docker run -d --env-file completion-kit.env completion-kit ./bin/jobs
|
|
253
|
+
```
|
|
254
|
+
|
|
255
|
+
Both processes must share the same `SECRET_KEY_BASE` and encryption keys — the single env file guarantees that. The web container runs `db:prepare` on boot, so migrations apply on first start and on every deploy.
|
|
256
|
+
|
|
220
257
|
## Multi-tenant host apps (advanced)
|
|
221
258
|
|
|
222
259
|
For hosts that mount CompletionKit in a multi-tenant app, two optional hooks scope engine records per tenant without forking the engine:
|
|
@@ -158,3 +158,9 @@ document.addEventListener("turbo:before-stream-render", function(event) {
|
|
|
158
158
|
if (status) { status.textContent = 'Models updated.'; setTimeout(function() { status.textContent = ' '; }, 3000); }
|
|
159
159
|
}
|
|
160
160
|
});
|
|
161
|
+
|
|
162
|
+
document.addEventListener("click", function(e) {
|
|
163
|
+
document.querySelectorAll("details.ck-nav-menu[open], details.ck-settings-menu[open], details.ck-flyout[open]").forEach(function(menu) {
|
|
164
|
+
if (!menu.contains(e.target)) menu.removeAttribute("open");
|
|
165
|
+
});
|
|
166
|
+
});
|
|
@@ -4345,6 +4345,16 @@ a.tag-mark {
|
|
|
4345
4345
|
.ck-settings-menu__trigger::-webkit-details-marker {
|
|
4346
4346
|
display: none;
|
|
4347
4347
|
}
|
|
4348
|
+
.ck-settings-menu__trigger svg {
|
|
4349
|
+
display: block;
|
|
4350
|
+
width: 18px;
|
|
4351
|
+
height: 18px;
|
|
4352
|
+
}
|
|
4353
|
+
.ck-settings-menu__trigger:focus-visible {
|
|
4354
|
+
outline: none;
|
|
4355
|
+
border-color: var(--ck-accent);
|
|
4356
|
+
color: var(--ck-accent);
|
|
4357
|
+
}
|
|
4348
4358
|
.ck-settings-menu__panel {
|
|
4349
4359
|
position: absolute;
|
|
4350
4360
|
right: 0;
|
|
@@ -4374,6 +4384,16 @@ a.tag-mark {
|
|
|
4374
4384
|
.ck-settings-menu__item:hover {
|
|
4375
4385
|
background: var(--ck-surface-hover);
|
|
4376
4386
|
}
|
|
4387
|
+
.ck-settings-menu__panel form {
|
|
4388
|
+
margin: 0;
|
|
4389
|
+
}
|
|
4390
|
+
.ck-settings-menu__panel button.ck-settings-menu__item {
|
|
4391
|
+
width: 100%;
|
|
4392
|
+
text-align: left;
|
|
4393
|
+
background: none;
|
|
4394
|
+
border: 0;
|
|
4395
|
+
cursor: pointer;
|
|
4396
|
+
}
|
|
4377
4397
|
|
|
4378
4398
|
/* Settings page kicker — small label above the page title on settings pages */
|
|
4379
4399
|
.ck-settings-kicker {
|
|
@@ -4961,3 +4981,71 @@ a.tag-mark {
|
|
|
4961
4981
|
max-height: 60vh;
|
|
4962
4982
|
}
|
|
4963
4983
|
}
|
|
4984
|
+
|
|
4985
|
+
.ck-concept {
|
|
4986
|
+
position: relative;
|
|
4987
|
+
display: inline;
|
|
4988
|
+
}
|
|
4989
|
+
.ck-concept__toggle {
|
|
4990
|
+
margin: 0 0 0 0.15rem;
|
|
4991
|
+
padding: 0;
|
|
4992
|
+
border: 0;
|
|
4993
|
+
background: none;
|
|
4994
|
+
font: inherit;
|
|
4995
|
+
line-height: 0;
|
|
4996
|
+
color: var(--ck-dim);
|
|
4997
|
+
cursor: pointer;
|
|
4998
|
+
}
|
|
4999
|
+
.ck-concept__toggle:hover,
|
|
5000
|
+
.ck-concept__toggle:focus {
|
|
5001
|
+
color: var(--ck-accent);
|
|
5002
|
+
}
|
|
5003
|
+
.ck-concept__icon {
|
|
5004
|
+
width: 0.92em;
|
|
5005
|
+
height: 0.92em;
|
|
5006
|
+
vertical-align: -0.12em;
|
|
5007
|
+
}
|
|
5008
|
+
.ck-concept__pop {
|
|
5009
|
+
display: none;
|
|
5010
|
+
position: absolute;
|
|
5011
|
+
top: calc(100% + 0.4rem);
|
|
5012
|
+
left: 0;
|
|
5013
|
+
z-index: 40;
|
|
5014
|
+
width: 19rem;
|
|
5015
|
+
max-width: calc(100vw - 1.5rem);
|
|
5016
|
+
padding: 0.7rem 0.8rem;
|
|
5017
|
+
background: var(--ck-bg-strong);
|
|
5018
|
+
border: 1px solid var(--ck-line-strong);
|
|
5019
|
+
border-radius: var(--ck-radius);
|
|
5020
|
+
box-shadow: 0 16px 34px rgba(0, 0, 0, 0.5);
|
|
5021
|
+
white-space: normal;
|
|
5022
|
+
}
|
|
5023
|
+
.ck-concept__toggle:hover + .ck-concept__pop,
|
|
5024
|
+
.ck-concept__toggle:focus + .ck-concept__pop,
|
|
5025
|
+
.ck-concept__pop:hover {
|
|
5026
|
+
display: block;
|
|
5027
|
+
}
|
|
5028
|
+
.ck-concept__name {
|
|
5029
|
+
display: block;
|
|
5030
|
+
margin-bottom: 0.3rem;
|
|
5031
|
+
font-family: var(--ck-mono);
|
|
5032
|
+
font-size: 0.72rem;
|
|
5033
|
+
font-weight: 700;
|
|
5034
|
+
letter-spacing: 0.06em;
|
|
5035
|
+
text-transform: uppercase;
|
|
5036
|
+
color: var(--ck-text);
|
|
5037
|
+
}
|
|
5038
|
+
.ck-concept__body {
|
|
5039
|
+
display: block;
|
|
5040
|
+
font-size: 0.8rem;
|
|
5041
|
+
line-height: 1.5;
|
|
5042
|
+
color: var(--ck-muted);
|
|
5043
|
+
}
|
|
5044
|
+
@media (max-width: 640px) {
|
|
5045
|
+
.ck-concept__pop {
|
|
5046
|
+
position: fixed;
|
|
5047
|
+
inset: auto 0.75rem 0.75rem 0.75rem;
|
|
5048
|
+
width: auto;
|
|
5049
|
+
max-width: none;
|
|
5050
|
+
}
|
|
5051
|
+
}
|
|
@@ -27,21 +27,21 @@
|
|
|
27
27
|
<%= link_to "Metrics", metrics_path, class: request.path.start_with?(metrics_path) || request.path.start_with?(metric_groups_path) ? ck_button_classes(:dark) : ck_button_classes(:light, variant: :outline) %>
|
|
28
28
|
<%= link_to "Datasets", datasets_path, class: active.(datasets_path) %>
|
|
29
29
|
<%= link_to "Runs", runs_path, class: active.(runs_path) %>
|
|
30
|
-
<% settings_active = request.path.start_with?(provider_credentials_path) || request.path.start_with?(tags_path) || request.path.start_with?(onboarding_path) %>
|
|
30
|
+
<% settings_active = request.path.start_with?(provider_credentials_path) || request.path.start_with?(tags_path) || request.path.start_with?(onboarding_path) || request.path.start_with?(api_reference_path) %>
|
|
31
31
|
<details class="ck-settings-menu">
|
|
32
32
|
<summary class="<%= settings_active ? ck_button_classes(:dark) : ck_button_classes(:light, variant: :outline) %> ck-settings-menu__trigger" aria-label="Settings">
|
|
33
|
-
|
|
33
|
+
<%= heroicon_tag "cog-6-tooth", variant: :outline, size: 18, "aria-hidden": "true" %>
|
|
34
34
|
</summary>
|
|
35
35
|
<div class="ck-settings-menu__panel" role="menu">
|
|
36
|
+
<%= link_to "Getting started", onboarding_path(reset: 1), class: "ck-settings-menu__item" %>
|
|
37
|
+
<%= link_to "API", api_reference_path, class: "ck-settings-menu__item" %>
|
|
36
38
|
<%= link_to "Providers", provider_credentials_path, class: "ck-settings-menu__item" %>
|
|
37
39
|
<%= link_to "Tags", tags_path, class: "ck-settings-menu__item" %>
|
|
38
|
-
|
|
40
|
+
<% if main_app.respond_to?(:logout_path) %>
|
|
41
|
+
<%= button_to "Sign out", main_app.logout_path, method: :delete, class: "ck-settings-menu__item" %>
|
|
42
|
+
<% end %>
|
|
39
43
|
</div>
|
|
40
44
|
</details>
|
|
41
|
-
<%= link_to "API", api_reference_path, class: active.(api_reference_path) %>
|
|
42
|
-
<% if main_app.respond_to?(:logout_path) %>
|
|
43
|
-
<%= button_to "Log out", main_app.logout_path, method: :delete, class: ck_button_classes(:light, variant: :outline) %>
|
|
44
|
-
<% end %>
|
|
45
45
|
</nav>
|
|
46
46
|
</details>
|
|
47
47
|
</div>
|