Skip to content

Add foundational docs: Getting Started, API Reference, History#321

Merged
brianmhunt merged 11 commits intomainfrom
docs/legacy-content
Apr 16, 2026
Merged

Add foundational docs: Getting Started, API Reference, History#321
brianmhunt merged 11 commits intomainfrom
docs/legacy-content

Conversation

@brianmhunt
Copy link
Copy Markdown
Member

@brianmhunt brianmhunt commented Apr 16, 2026

Summary

  • Getting Started — installation guide (CDN, package manager, TypeScript), browser support
  • API Reference — quick-lookup index linking to all detailed docs pages
  • Utility Functions — type checking, unwrapping, serialization, .fn extensibility
  • Loading & Saving Datako.toJS/ko.toJSON, fetch patterns, debugging
  • History — Knockout origins, Big Four era, Microsoft/enterprise adoption, why TKO in 2026
  • Updated hero copy: "Battle-tested since 2010 / Ship in seconds"
  • Primary CTA now links to Getting Started

Closes gaps identified from legacy Knockout documentation audit (issues #141, #167).

Test plan

  • All new pages render at localhost:4321
  • All internal links resolve (verified locally, all 200)
  • Sidebar navigation order is correct
  • Mobile viewport renders properly

🤖 Generated with Claude Code

Summary by CodeRabbit

  • Documentation
    • Added Getting Started guides including installation methods, browser support, and first binding examples
    • Added API reference index for quick lookup of observables, bindings, components, and utilities
    • Added Observable utilities documentation covering type checking, unwrapping, serialization, and extensibility
    • Added guide for loading and saving JSON data with observables
    • Added History page and updated navigation structure
    • Updated landing page messaging

New pages:
- Getting Started: installation guide (CDN, package manager, TypeScript)
- Browser Support: engine coverage, CI testing, ESM vs classic script
- API Reference: quick-lookup index linking to detailed docs
- Utility Functions: type checking, unwrapping, serialization, .fn
- Loading & Saving Data: toJS/toJSON, fetch patterns, debugging
- History: Knockout origins, Big Four era, enterprise adoption, why TKO in 2026

Also:
- Update hero: "Battle-tested since 2010 / Ship in seconds"
- Primary CTA links to Getting Started instead of Bindings
- Sidebar: add Getting Started, API Reference, History sections

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings April 16, 2026 16:59
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Apr 16, 2026

Warning

Rate limit exceeded

@brianmhunt has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 42 minutes and 8 seconds before requesting another review.

Your organization is not enrolled in usage-based pricing. Contact your admin to enable usage-based pricing to continue reviews beyond the rate limit, or try again in 42 minutes and 8 seconds.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 2c5f16d0-04df-4e8f-87df-24ce0f4f49a1

📥 Commits

Reviewing files that changed from the base of the PR and between c11c217 and 5425ba0.

📒 Files selected for processing (10)
  • tko.io/astro.config.mjs
  • tko.io/src/content/docs/api.md
  • tko.io/src/content/docs/getting-started/browser-support.md
  • tko.io/src/content/docs/getting-started/deploy.md
  • tko.io/src/content/docs/getting-started/index.mdx
  • tko.io/src/content/docs/history.md
  • tko.io/src/content/docs/index.mdx
  • tko.io/src/content/docs/observables/json-data.md
  • tko.io/src/content/docs/observables/utilities.md
  • tko.io/src/styles/tko.css
📝 Walkthrough

Walkthrough

This PR introduces comprehensive documentation for the TKO project, adding an installation guide, browser support details, API reference index, observable utilities and JSON data handling documentation, a project history page, and updates the landing page messaging and Starlight sidebar configuration to reflect the new documentation structure.

Changes

Cohort / File(s) Summary
Documentation Plan & Configuration
plans/legacy-docs.md, tko.io/astro.config.mjs
New documentation planning document outlining five fresh Starlight pages and required sidebar configuration. Config updated with "Getting Started" auto-generation, "API Reference", and "History" entries.
Getting Started Guides
tko.io/src/content/docs/getting-started/index.mdx, tko.io/src/content/docs/getting-started/browser-support.md
New installation guide with CDN, package manager, and first-binding examples using tabs for variant selection. Browser support page documents ES2020+ targets, supported rendering engines, and dual loading methods (ESM and classic script fallback).
API & Historical Reference
tko.io/src/content/docs/api.md, tko.io/src/content/docs/history.md
New API reference index providing quick-lookup sections for Observables, Computed, Extenders, Bindings, Components, and Utilities. History page chronicles TKO's evolution from Knockout.js (2010–2016+) including enterprise adoption and 2026 AI-assisted development rationale.
Observable Utilities & Data Handling
tko.io/src/content/docs/observables/utilities.md, tko.io/src/content/docs/observables/json-data.md
New utilities documentation covering type-checking helpers, unwrapping, serialization via ko.toJS/ko.toJSON, and .fn prototype extensibility. JSON data page documents patterns for transferring data between server and observable state using serialization and an updateFrom helper.
Landing Page
tko.io/src/content/docs/index.mdx
Updated hero messaging from "Modern Knockout, clarified" to "Battle-tested since 2010" with new tagline emphasizing zero dependencies and fast setup. Primary CTA link changed from /bindings/ to /getting-started/.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~12 minutes

Possibly related PRs

  • Add interactive examples showcase #291: Modifies tko.io/astro.config.mjs sidebar configuration by inserting additional top-level navigation entries (Examples), directly overlapping this PR's sidebar updates.
  • Refine tko.io landing page #317: Updates tko.io/src/content/docs/index.mdx landing hero content and structure, overlapping this PR's landing page messaging changes.
  • New tko io site #227: Involves migration of the tko.io site including astro.config.mjs and src/content/docs structural changes, directly relevant to this PR's documentation infrastructure updates.

Poem

🐰 Fresh docs hop into view,
Installation, API, history too!
Observable guides and JSON flows clear,
The warren of knowledge is finally here! 📚✨

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title directly summarizes the main changes: addition of foundational documentation covering Getting Started, API Reference, and History sections, which aligns with the primary objective of closing gaps in legacy documentation.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch docs/legacy-content

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: c11c217004

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

TKO is written in TypeScript. Types are included — no separate `@types` package needed.

```ts
import ko, { Observable } from '@tko/build.reference'
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Import Observable from a package that exports it

The TypeScript quickstart currently suggests import ko, { Observable } from '@tko/build.reference', but @tko/build.reference only re-exports its default instance (see builds/reference/src/index.ts), so this named import will fail type-checking for users who copy the example. This makes the primary TS onboarding snippet non-functional; use a type source that is actually exported (for example from @tko/observable) or a type inferred from ko.observable.

Useful? React with 👍 / 👎.

| Function | Description |
|----------|-------------|
| `ko.components.register(name, config)` | Register a component. [Docs](/components/component-registration/) |
| `ko.components.get(name)` | Retrieve a registered component definition. [Docs](/components/component-loaders/) |
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Document ko.components.get with its required callback

This API row omits the callback parameter, but ko.components.get is callback-based (ko.components.get(name, callback)), and the implementation invokes callback(...) unconditionally (packages/utils.component/src/registry.ts). Readers following this signature will call it with only name and hit runtime errors or unresolved behavior, so the reference should show the actual callable form.

Useful? React with 👍 / 👎.

Comment on lines +1 to +3
---
title: API Reference
description: Quick-lookup index of TKO's public API.
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Update agent docs when adding new API/doc pages

Per /workspace/tko/AGENTS.md, documentation updates involving new APIs/patterns must update both Starlight docs and the agent guide (tko.io/public/agents/guide.md). This commit adds major new pages (Getting Started, API Reference, utilities/data patterns, history) but does not update the agent-facing guide, which leaves agent documentation stale and out of sync with the new canonical docs.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 4

🧹 Nitpick comments (2)
tko.io/src/content/docs/history.md (1)

18-21: Add citations for high-specificity historical/quantitative claims.

Several exact figures and historical assertions would benefit from inline sources to improve trust and long-term maintainability of this page.

Also applies to: 41-42, 71-75

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@tko.io/src/content/docs/history.md` around lines 18 - 21, Add inline
citations for the specific historical and quantitative claims in the two
sentences that assert ThoughtWorks placed Knockout in the Technology Radar
"Trial" ring and that Knockout peaked in Stack Overflow question volume with a
69.6% answer rate; find and insert reliable sources (e.g., ThoughtWorks
Technology Radar archive, Stack Overflow data explorer or blog posts, and any
contemporaneous analyses) as inline links or footnote references next to those
sentences, and apply the same treatment to the other similar claims elsewhere in
the document (the other high-specificity figures and historical assertions) so
each precise number or event is backed by a citation.
tko.io/src/content/docs/observables/utilities.md (1)

73-76: Clarify the prototype-chain diagram to use .fn consistently.

observableArray in the chain reads like the constructor/type, while this section is specifically about .fn extension points. Consider naming it observableArray.fn to avoid ambiguity.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@tko.io/src/content/docs/observables/utilities.md` around lines 73 - 76, The
prototype-chain diagram mixes constructor names and `.fn` extension points;
change the third entry from `observableArray` to `observableArray.fn` so the
chain reads `subscribable.fn → observable.fn → observableArray.fn (extends
observable.fn) → computed.fn`, ensuring consistent `.fn` notation across
`subscribable.fn`, `observable.fn`, `observableArray.fn`, and `computed.fn`.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@tko.io/src/content/docs/api.md`:
- Around line 1-74: The API docs add/changed many public symbols (e.g.,
ko.observable, ko.observableArray, ko.unwrap, ko.toJS, ko.computed,
ko.pureComputed, ko.when, observable.extend and extenders like
rateLimit/notify:'always', ko.applyBindings, ko.applyBindingsToNode,
ko.bindingHandlers, ko.components.register/get/isRegistered/unregister and
binding names like text/html/value/foreach/if/visible/css/style/attr) but the
agent-facing guidance wasn't updated; update the agent guide files (guide.md,
contract.md, testing.md in the repo's agent docs) to mirror these new/changed
APIs and behaviors: enumerate each new API entry and its expected behavior and
surface-level usage examples for agents, update component/ binding lists and
extenders and their semantics, and add testable contracts and example test
prompts for agents to validate behavior (e.g., verifying
ko.observable/ko.computed reactivity, ko.applyBindings usage, component
registration/loading, and extenders like rateLimit/notify).

In `@tko.io/src/content/docs/getting-started/browser-support.md`:
- Line 31: Wording conflicts with the earlier browser target — change the
sentence "An IIFE build is also available for environments that don't support ES
modules:" to clarify intent by saying something like "An IIFE build is also
available for classic script-tag loading (for browsers that do not use ES
modules):" so it reads as an alternative loading method rather than implying
broader browser targeting.

In `@tko.io/src/content/docs/observables/json-data.md`:
- Around line 68-71: The usage snippet uses top-level await (const data = await
fetch(...)) which is invalid in non-ESM contexts; update the example around
fetch, updateFrom and vm to run inside an async context (e.g., wrap the
fetch/await/updateFrom sequence in an async function or provide a Promise-based
.then() alternative) so the snippet is portable across CommonJS and classic
script tags.

In `@tko.io/src/content/docs/observables/utilities.md`:
- Around line 1-92: The Starlight docs add new observable utilities but the
AI-facing agent guides under public agents weren't updated; add corresponding
agent-guide entries for ko.isObservable, ko.isWritableObservable, ko.isComputed,
ko.isSubscribable, ko.unwrap, ko.toJS, ko.toJSON, and the
observable/subscribable `.fn` extension pattern in the agents docs so the agent
knowledge matches the human docs — include short descriptions, usage examples
(inputs/outputs), edge cases (e.g., read-only computed vs writable observable),
and update the agents TOC/indexing so these symbols are discoverable by agents.

---

Nitpick comments:
In `@tko.io/src/content/docs/history.md`:
- Around line 18-21: Add inline citations for the specific historical and
quantitative claims in the two sentences that assert ThoughtWorks placed
Knockout in the Technology Radar "Trial" ring and that Knockout peaked in Stack
Overflow question volume with a 69.6% answer rate; find and insert reliable
sources (e.g., ThoughtWorks Technology Radar archive, Stack Overflow data
explorer or blog posts, and any contemporaneous analyses) as inline links or
footnote references next to those sentences, and apply the same treatment to the
other similar claims elsewhere in the document (the other high-specificity
figures and historical assertions) so each precise number or event is backed by
a citation.

In `@tko.io/src/content/docs/observables/utilities.md`:
- Around line 73-76: The prototype-chain diagram mixes constructor names and
`.fn` extension points; change the third entry from `observableArray` to
`observableArray.fn` so the chain reads `subscribable.fn → observable.fn →
observableArray.fn (extends observable.fn) → computed.fn`, ensuring consistent
`.fn` notation across `subscribable.fn`, `observable.fn`, `observableArray.fn`,
and `computed.fn`.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 49c229e3-962c-4686-af43-ce460e50b1e1

📥 Commits

Reviewing files that changed from the base of the PR and between bd644ad and c11c217.

📒 Files selected for processing (9)
  • plans/legacy-docs.md
  • tko.io/astro.config.mjs
  • tko.io/src/content/docs/api.md
  • tko.io/src/content/docs/getting-started/browser-support.md
  • tko.io/src/content/docs/getting-started/index.mdx
  • tko.io/src/content/docs/history.md
  • tko.io/src/content/docs/index.mdx
  • tko.io/src/content/docs/observables/json-data.md
  • tko.io/src/content/docs/observables/utilities.md

Comment on lines +1 to +74
---
title: API Reference
description: Quick-lookup index of TKO's public API.
---

# API Reference

Quick-lookup table for TKO's public API. Each entry links to its detailed documentation.

## Observables

| Function | Description |
|----------|-------------|
| `ko.observable(value?)` | Create a reactive value. [Docs](/observables/) |
| `ko.observableArray(array?)` | Observable wrapper around an array with mutation methods. [Docs](/observables/observablearrays/) |
| `ko.isObservable(value)` | Check if a value is an observable. [Docs](/observables/utilities/) |
| `ko.isWritableObservable(value)` | Check if a value is a writable observable. [Docs](/observables/utilities/) |
| `ko.isSubscribable(value)` | Check if a value is any subscribable type. [Docs](/observables/utilities/) |
| `ko.unwrap(value)` | Read an observable's value, or return a plain value as-is. [Docs](/observables/utilities/) |
| `ko.toJS(object)` | Clone an object tree, replacing observables with their values. [Docs](/observables/utilities/) |
| `ko.toJSON(object, replacer?, space?)` | `ko.toJS` + `JSON.stringify`. [Docs](/observables/utilities/) |

## Computed

| Function | Description |
|----------|-------------|
| `ko.computed(evaluator, owner?, options?)` | Create a value that depends on other observables. [Docs](/computed/computedobservables/) |
| `ko.pureComputed(evaluator, owner?)` | Computed that sleeps when it has no subscribers. [Docs](/computed/computed-pure/) |
| `ko.isComputed(value)` | Check if a value is a computed observable. [Docs](/observables/utilities/) |
| `ko.when(predicate)` | Return a promise that resolves when the predicate becomes truthy. [Docs](/observables/) |

## Extenders

| Function | Description |
|----------|-------------|
| `observable.extend(extenders)` | Apply extenders to an observable or computed. [Docs](/observables/extenders/) |
| `rateLimit` | Throttle change notifications. [Docs](/observables/ratelimit-observable/) |
| `notify: 'always'` | Force notification even when value hasn't changed. [Docs](/observables/) |

## Bindings

| Function | Description |
|----------|-------------|
| `ko.applyBindings(viewModel, rootNode?)` | Activate bindings on a DOM subtree. [Docs](/observables/#activating-knockout) |
| `ko.applyBindingsToNode(node, bindings, viewModel?)` | Apply bindings to a single node programmatically. |
| `ko.cleanNode(node)` | Remove all TKO data and bindings from a node. |
| `ko.bindingHandlers` | Registry of built-in and custom binding handlers. [Docs](/binding-context/custom-bindings/) |

### Built-in bindings

**Text & HTML:** [`text`](/bindings/text-binding/), [`html`](/bindings/html-binding/), [`textInput`](/bindings/textinput-binding/), [`value`](/bindings/value-binding/)

**Appearance:** [`visible`](/bindings/visible-binding/), [`css`](/bindings/css-binding/), [`style`](/bindings/style-binding/), [`attr`](/bindings/attr-binding/)

**Control flow:** [`if`](/bindings/if-binding/), [`ifnot`](/bindings/ifnot-binding/), [`foreach`](/bindings/foreach-binding/), [`with`](/bindings/with-binding/), [`template`](/bindings/template-binding/)

**Form:** [`click`](/bindings/click-binding/), [`event`](/bindings/event-binding/), [`submit`](/bindings/submit-binding/), [`enable`](/bindings/enable-binding/), [`disable`](/bindings/disable-binding/), [`checked`](/bindings/checked-binding/), [`options`](/bindings/options-binding/), [`selectedOptions`](/bindings/selectedoptions-binding/), [`hasfocus`](/bindings/hasfocus-binding/), [`uniqueName`](/bindings/uniquename-binding/)

## Components

| Function | Description |
|----------|-------------|
| `ko.components.register(name, config)` | Register a component. [Docs](/components/component-registration/) |
| `ko.components.get(name)` | Retrieve a registered component definition. [Docs](/components/component-loaders/) |
| `ko.components.isRegistered(name)` | Check if a component name is registered. |
| `ko.components.unregister(name)` | Remove a component registration. |

## Utilities

| Function | Description |
|----------|-------------|
| `ko.observable.fn` | Prototype for all observables — add methods here. [Docs](/observables/utilities/) |
| `ko.subscribable.fn` | Prototype for all subscribables. [Docs](/observables/utilities/) |
| `ko.computed.fn` | Prototype for all computeds. [Docs](/observables/utilities/) |
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Sync tko.io/public/agents/ docs with these new API/behavior pages.

This PR adds substantial API and behavioral documentation, but the provided changes do not include corresponding agent-guide updates. That creates human/agent documentation drift.

If helpful, I can draft the matching updates for tko.io/public/agents/guide.md, tko.io/public/agents/contract.md, and tko.io/public/agents/testing.md in the same style.
As per coding guidelines tko.io/**/*.{md,mdx}: “Update both Starlight docs (for humans) and agent guides in tko.io/public/agents/ (for AI agents) when documentation changes for new APIs, bindings, or behavioral changes”.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@tko.io/src/content/docs/api.md` around lines 1 - 74, The API docs add/changed
many public symbols (e.g., ko.observable, ko.observableArray, ko.unwrap,
ko.toJS, ko.computed, ko.pureComputed, ko.when, observable.extend and extenders
like rateLimit/notify:'always', ko.applyBindings, ko.applyBindingsToNode,
ko.bindingHandlers, ko.components.register/get/isRegistered/unregister and
binding names like text/html/value/foreach/if/visible/css/style/attr) but the
agent-facing guidance wasn't updated; update the agent guide files (guide.md,
contract.md, testing.md in the repo's agent docs) to mirror these new/changed
APIs and behaviors: enumerate each new API entry and its expected behavior and
surface-level usage examples for agents, update component/ binding lists and
extenders and their semantics, and add testable contracts and example test
prompts for agents to validate behavior (e.g., verifying
ko.observable/ko.computed reactivity, ko.applyBindings usage, component
registration/loading, and extenders like rateLimit/notify).

Comment thread tko.io/src/content/docs/getting-started/browser-support.md Outdated
Comment thread tko.io/src/content/docs/observables/json-data.md
Comment on lines +1 to +92
---
title: Utility Functions
---

# Utility functions

TKO provides helper functions for inspecting and converting observables.

## Type checking

| Function | Returns `true` when |
|----------|-------------------|
| `ko.isObservable(value)` | The value is an observable, observable array, or computed |
| `ko.isWritableObservable(value)` | The value is a writable observable (not a read-only computed) |
| `ko.isComputed(value)` | The value is a computed observable |
| `ko.isSubscribable(value)` | The value is any subscribable (observable, computed, or raw subscribable) |

```js
const name = ko.observable('TKO')
const upper = ko.computed(() => name().toUpperCase())

ko.isObservable(name) // true
ko.isObservable(upper) // true
ko.isObservable('plain') // false
ko.isWritableObservable(name) // true
ko.isWritableObservable(upper) // false
ko.isComputed(upper) // true
```

## Unwrapping

`ko.unwrap(value)` reads the value if it's an observable, or returns it as-is if it isn't. Useful when a function accepts either an observable or a plain value:

```js
ko.unwrap(ko.observable(42)) // 42
ko.unwrap(42) // 42
```

This is commonly used inside custom bindings where a parameter could be either type.

## Serialization

`ko.toJS` and `ko.toJSON` convert an object graph containing observables into plain data.

`ko.toJS(viewModel)` — clones the object tree, replacing every observable with its current value:

```js
const vm = {
name: ko.observable('TKO'),
tags: ko.observableArray(['fast', 'reactive']),
nested: {
count: ko.observable(3)
}
}

ko.toJS(vm)
// { name: 'TKO', tags: ['fast', 'reactive'], nested: { count: 3 } }
```

`ko.toJSON(viewModel, replacer?, space?)` — same as `ko.toJS` followed by `JSON.stringify`. Accepts the same optional `replacer` and `space` arguments as `JSON.stringify`:

```js
ko.toJSON(vm, null, 2)
// Pretty-printed JSON string
```

See [Loading & Saving Data](./json-data/) for practical patterns.

## Extending types with `.fn`

Every observable inherits from a prototype chain you can extend:

```
subscribable.fn → observable.fn → observableArray (extends observable.fn)
→ computed.fn
```

Adding a method to `ko.observable.fn` makes it available on all observables:

```js
ko.observable.fn.log = function (label) {
this.subscribe(value => console.log(label, value))
return this
}

const name = ko.observable('TKO').log('name changed:')
name('v5') // console: "name changed: v5"
```

Adding to `ko.subscribable.fn` affects everything — observables, computed, and observable arrays.

Use `.fn` when the behavior is broadly useful. For one-off logic, prefer a regular function or [extender](/observables/extenders/) instead.
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Verify whether this PR includes required agent-doc updates alongside Starlight docs.
# Expected: at least one changed file under tko.io/public/agents/ when API/binding behavior docs change.

git diff --name-only origin/main...HEAD | rg '^tko\.io/public/agents/.*\.md$' -n

Repository: knockout/tko

Length of output: 96


🏁 Script executed:

#!/bin/bash
# List files in tko.io/public/agents/ to understand agent-guide structure
echo "=== Files in tko.io/public/agents/ ==="
find tko.io/public/agents -type f -name "*.md" 2>/dev/null | sort

# Check if tko.io/public/ exists and what's in it
echo -e "\n=== Structure of tko.io/public/ ==="
ls -la tko.io/public/ 2>/dev/null || echo "Directory not found or not accessible"

# Try to get git status in a different way
echo -e "\n=== Checking git HEAD and available refs ==="
git rev-parse HEAD 2>/dev/null || echo "HEAD not available"
git show-ref 2>/dev/null | head -20 || echo "No refs found"

Repository: knockout/tko

Length of output: 2619


🏁 Script executed:

#!/bin/bash
# Compare current HEAD with origin/main to see what files changed in this PR
echo "=== Files changed in this PR (HEAD vs origin/main) ==="
git diff --name-only origin/main HEAD 2>/dev/null || git diff --name-only HEAD~1 HEAD 2>/dev/null | head -50

echo -e "\n=== Specifically, any changes in tko.io/public/agents/? ==="
git diff --name-only origin/main HEAD 2>/dev/null | rg '^tko\.io/public/agents' || echo "No agent-doc changes found"

echo -e "\n=== Check content of existing utils.md in agent guides ==="
head -50 tko.io/public/agents/verified-behaviors/utils.md

Repository: knockout/tko

Length of output: 3014


Add agent-guide documentation for the new observable utility APIs.

This PR introduces new API documentation for ko.isObservable, ko.isWritableObservable, ko.isComputed, ko.isSubscribable, ko.unwrap, ko.toJS, and .fn extension patterns in the Starlight docs, but doesn't include corresponding updates to the agent guides in tko.io/public/agents/. Per the coding guidelines, both human-facing (Starlight) and AI-facing (agent guides) documentation must be updated together when new APIs or behavioral changes are documented.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@tko.io/src/content/docs/observables/utilities.md` around lines 1 - 92, The
Starlight docs add new observable utilities but the AI-facing agent guides under
public agents weren't updated; add corresponding agent-guide entries for
ko.isObservable, ko.isWritableObservable, ko.isComputed, ko.isSubscribable,
ko.unwrap, ko.toJS, ko.toJSON, and the observable/subscribable `.fn` extension
pattern in the agents docs so the agent knowledge matches the human docs —
include short descriptions, usage examples (inputs/outputs), edge cases (e.g.,
read-only computed vs writable observable), and update the agents TOC/indexing
so these symbols are discoverable by agents.

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Adds foundational documentation pages to the tko.io Starlight site to close gaps from the legacy Knockout docs audit, and updates the docs landing page + sidebar to route newcomers through a Getting Started flow.

Changes:

  • Added new docs pages: Getting Started (installation + browser support), API Reference, History, and new Observables pages (Utilities + Loading/Saving JSON data).
  • Updated the docs landing hero/CTA to point to “Get started”.
  • Updated tko.io/astro.config.mjs sidebar to include “Getting Started”, “API Reference”, and “History”.

Reviewed changes

Copilot reviewed 9 out of 9 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
tko.io/src/content/docs/observables/utilities.md New “Utility Functions” page (type-checking, unwrap, serialization, .fn extensibility).
tko.io/src/content/docs/observables/json-data.md New “Loading & Saving Data” page showing ko.toJS/ko.toJSON patterns.
tko.io/src/content/docs/index.mdx Updates hero copy and primary CTA to link to Getting Started.
tko.io/src/content/docs/history.md Adds project/history narrative page for Knockout → TKO context.
tko.io/src/content/docs/getting-started/index.mdx New installation/overview page with CDN + package manager + TS notes.
tko.io/src/content/docs/getting-started/browser-support.md New browser support + CI testing overview page.
tko.io/src/content/docs/api.md New API quick-lookup index linking to detailed docs pages.
tko.io/astro.config.mjs Sidebar updates to surface Getting Started / API / History.
plans/legacy-docs.md Adds a plan doc describing the docs additions and verification steps.

Comment on lines +110 to +112
import ko, { Observable } from '@tko/build.reference'

const name: Observable<string> = ko.observable('TKO')
Copy link

Copilot AI Apr 16, 2026

Choose a reason for hiding this comment

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

The TypeScript snippet imports { Observable } from @tko/build.reference, but the build.reference entrypoint only re-exports the default build object (no named Observable export), so this example won’t type-check. Update the snippet to either rely on generic inference (ko.observable<string>(...)) or import the Observable type from the package that actually exports it (e.g. @tko/observable) if you want an explicit annotation.

Suggested change
import ko, { Observable } from '@tko/build.reference'
const name: Observable<string> = ko.observable('TKO')
import ko from '@tko/build.reference'
const name = ko.observable<string>('TKO')

Copilot uses AI. Check for mistakes.
Comment thread tko.io/src/content/docs/api.md Outdated
| `ko.computed(evaluator, owner?, options?)` | Create a value that depends on other observables. [Docs](/computed/computedobservables/) |
| `ko.pureComputed(evaluator, owner?)` | Computed that sleeps when it has no subscribers. [Docs](/computed/computed-pure/) |
| `ko.isComputed(value)` | Check if a value is a computed observable. [Docs](/observables/utilities/) |
| `ko.when(predicate)` | Return a promise that resolves when the predicate becomes truthy. [Docs](/observables/) |
Copy link

Copilot AI Apr 16, 2026

Choose a reason for hiding this comment

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

ko.when(predicate) is documented under the computed observables docs (see the “Waiting for a condition with ko.when” section in /computed/computedobservables/), but this table links it to /observables/. Update the link so the API reference points to the page/section that actually documents ko.when.

Suggested change
| `ko.when(predicate)` | Return a promise that resolves when the predicate becomes truthy. [Docs](/observables/) |
| `ko.when(predicate)` | Return a promise that resolves when the predicate becomes truthy. [Docs](/computed/computedobservables/#waiting-for-a-condition-with-ko-when) |

Copilot uses AI. Check for mistakes.
Every observable inherits from a prototype chain you can extend:

```
subscribable.fn → observable.fn → observableArray (extends observable.fn)
Copy link

Copilot AI Apr 16, 2026

Choose a reason for hiding this comment

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

The .fn prototype-chain diagram is a bit misleading: observableArray instances inherit from ko.observableArray.fn (not observableArray), and computed.fn is a sibling branch off subscribable.fn rather than something that comes “after” observable.fn. Adjusting the diagram labels/arrows would make it match the actual extension points (ko.subscribable.fn, ko.observable.fn, ko.observableArray.fn, ko.computed.fn).

Suggested change
subscribable.fn → observable.fn → observableArray (extends observable.fn)
subscribable.fn → observable.fn → observableArray.fn

Copilot uses AI. Check for mistakes.
title: Browser Support
---

TKO targets modern browsers — any browser that supports ES2020 and `<script type="module">`.
Copy link

Copilot AI Apr 16, 2026

Choose a reason for hiding this comment

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

The opening line states ES module support requires “ES2020”, but the page also recommends the IIFE build for non-module environments. It would be clearer to distinguish the requirements: the ESM/CDN import path may require ES2020+ features, while the dist/browser*.js IIFE build is transpiled to an older target (built with esbuild --target=es6).

Suggested change
TKO targets modern browsers — any browser that supports ES2020 and `<script type="module">`.
TKO's recommended ES module build targets modern browsers that support ES2020 and `<script type="module">`. For older non-module environments, the `dist/browser*.js` IIFE build is also available and is transpiled to ES6.

Copilot uses AI. Check for mistakes.
Brian M Hunt and others added 10 commits April 16, 2026 13:47
- Add inline citations to history page (ThoughtWorks, SO blog, NuGet, VS Live)
- Fix .fn diagram to use observableArray.fn consistently
- Clarify IIFE as classic script-tag loading
- Wrap top-level await in async function
- Restyle version as clickable pill above hero (bun.sh-inspired)
- Hero heading: "Battle-tested since 2010 / Ship a dynamic web UI in seconds"
- Remove content panel border/radius for cleaner layout
- Add history page to sidebar

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Add missing APIs: isObservableArray, peek, isPureComputed, ignoreDependencies,
  contextFor, dataFor, applyBindingsToDescendants, BindingHandler,
  AsyncBindingHandler, bindingEvent, Component, JSX, domNodeDisposal, tasks
- Add missing bindings: let, using, hidden, each, unless, else/elseif,
  component, slot, checkedValue, descendantsComplete, plus aliases
- Add subscribable instance methods: when, yet, next, once, peek, dispose
- Add isObservableArray to utilities.md type-checking table
- Fix TypeScript example (remove non-existent named import)
- Fix ko.computed and ko.when signatures
- Add inline citations to history page
- Restyle version as clickable pill, hero heading large/bold
- Remove content panel border for cleaner layout

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Bindings, Observables, Computed, Components, Binding Context, and
Advanced all start collapsed. Getting Started, Examples, API Reference,
and History remain visible at the top/bottom.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- New getting-started/deploy.md: GitHub Pages, Cloudflare Pages, GCS,
  Firebase Hosting, Netlify — fulfills the "ship in seconds" promise
- Hero: "TKO" as massive heading, "Battle-tested since 2010" as kicker
- Browser support: honest about untested older versions, invite bug reports

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The ESM import may not work in all playground/sandbox environments.
IIFE via jsdelivr is more universally compatible.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@brianmhunt brianmhunt merged commit e4441a3 into main Apr 16, 2026
8 checks passed
@brianmhunt brianmhunt deleted the docs/legacy-content branch April 16, 2026 18:49
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants