Skip to content
Merged
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
36 changes: 29 additions & 7 deletions .agents/references/terminology.md
Original file line number Diff line number Diff line change
Expand Up @@ -182,10 +182,10 @@ catches the literal, `platform-determiner` catches a missing article.
*Example:* With the Automation Platform, you can orchestrate multiple agents to automate and parallelize complex workflows.

- **cloud agent dashboard** — The app surface to manage all runs, unified across the Warp app and web.
*Usage note:* Platform-level default (HYC, 2026-08-17). Use `{VARS.DASHBOARD}`. On pages specifically about a factory, write "Factory dashboard" directly. Lowercase common noun, so capitalize only at the start of a sentence or bullet — which the variable cannot do, so reword rather than leading a bullet with it.
*Usage note:* Platform-level default (HYC, 2026-08-17). Use `{VARS.DASHBOARD}`. On pages specifically about a factory, write "factory dashboard" directly. Both are lowercase common nouns, so capitalize only at the start of a sentence or bullet — which the variable cannot do, so reword rather than leading a bullet with it.

- **cloud agent run** — A single execution lifecycle of an agent, including actions, outputs, and logs. Always cloud-based.
*Usage note:* This is the platform-level default (HYC, 2026-08-17). Use `{VARS.PLATFORM_RUN}`, or "Warp cloud agent run" when you need to disambiguate from another vendor's runs. On pages that are specifically about a factory, write "Factory run" directly instead — the variable holds the general term, so it cannot carry that distinction.
*Usage note:* This is the platform-level default (HYC, 2026-08-17). Use `{VARS.PLATFORM_RUN}`, or "Warp cloud agent run" when you need to disambiguate from another vendor's runs. On pages that are specifically about a factory, write "factory run" directly instead — the variable holds the general term, so it cannot carry that distinction.

- **Oz web app** — The web app for configuring agents and managing runs.
*Usage note:* Holds the Oz name until 2026-09-15. Use `{VARS.WEB_APP}`.
Expand Down Expand Up @@ -278,8 +278,30 @@ Not every "Oz" in the docs is stale. These are deliberate and correct until

## Warp Factories terminology

- **Warp Factories** — Warp's product for deploying and operating cloud software factories: automation loops around the SDLC where cloud agents triage, spec, implement, review, and verify work, with humans in the loop at key decision points. Launches in closed beta ~2026-08-18.
*Usage note:* Capitalize both words as the product name; plural "Factories." Distinct from "software factory" (see below), the generic industry term for the pattern.
### The product/instance rule

This works like GitHub Actions. **Warp Factories** is the product and is always
written in full. An individual **factory** is a common noun and is always
lowercase. A bare capitalized **Factory** is never a proper noun — there is no
such product.

- ✅ "Warp Factories is in Early Access" (the product)
- ✅ "your factory", "each factory's agents", "set up a factory" (an instance)
- ✅ "factory dashboard", "factory run", "factory agents", "factory definition"
- ❌ "the Factory", "your Factory", "Factory runs", "Factory metrics"
- ❌ "Factories" on its own to mean the product — write "Warp Factories"

Sentence-initial capitals are positional, not proper nouns: a heading, sidebar
label, or page title may begin "Factory agents" or "Factory dashboard" for the
same reason it would begin "Cloud agents." The rule governs mid-sentence prose.

Verbatim product strings are quoted as they ship, even when they break the rule.
The setup wizard currently renders **Factory name**, **Add your Factory to your
team**, and "Factory running!", and the sidebar renders **Factory definition**.
Docs match the screen; the fix belongs in the app.

- **Warp Factories** — Warp's product for deploying and operating cloud software factories: automation loops around the SDLC where cloud agents triage, spec, implement, review, and verify work, with humans in the loop at key decision points. Launched in Early Access 2026-08-18.
*Usage note:* Capitalize both words as the product name; plural "Factories." Always write it in full — never a bare "Factory" or "Factories." Distinct from "software factory" (see below), the generic industry term for the pattern.

- **software factory** — The generic, lowercase industry term for an automation loop around the SDLC (triage, spec, implement, review, verify). Warp Factories is Warp's product implementation of this pattern.
*Usage note:* Lowercase when used generically ("a software factory," "cloud software factories"). Capitalize only when part of the product name "Warp Factories."
Expand All @@ -294,10 +316,10 @@ Not every "Oz" in the docs is stale. These are deliberate and correct until
- **foreman agent** — The orchestrator agent that receives a work item's triggering context and dispatches subagents to move it through the factory, choosing model, harness, and context for each step.

- **Factory MCP** — The MCP server that lets any coding agent or MCP client interact with a factory: push work in, pull status, or guide sessions.
*Usage note:* Capitalize as a feature/proper-noun name.
*Usage note:* The one sanctioned exception to the product/instance rule above, because it is the feature's own shipped name — the server registers as `warp-factory` and its skill calls itself "the Warp Factory MCP." Capitalize both words; do not generalize the exception to other phrases.

- **control room** — The web app view showing all factory agent runs, work item status, automations, and configuration for a given factory.
*Usage note:* Lowercase common noun unless referring to a specific labeled UI element.
- **factory dashboard** — The web app surface for operating a single factory: its work items, runs, agents, automations, and settings.
*Usage note:* Lowercase common noun. Distinct from **Dashboard**, the metrics page inside it, which is also the factory's landing page — bold **Dashboard** when you mean that page, and leave "factory dashboard" unbolded when you mean the surface. Replaced "control room," a docs-only coinage that appeared nowhere in the product.

- **AI sovereignty** — Warp Factories' positioning around customer ownership and control of inference, hosting, and data exhaust (agent conversations, evals, memories) for their factory.

Expand Down
11 changes: 11 additions & 0 deletions .agents/skills/style_lint/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ python3 .agents/skills/style_lint/style_lint.py --all --fix --create-pr
- **Deprecated terminology**: "whitelist" (→ "allowlist"), "blacklist"/"blocklist" (→ "denylist")
- **External product names**: "Github" (→ "GitHub"), "github actions" (→ "GitHub Actions"), "MacOS" (→ "macOS"), "A.I." (→ "AI")
- **Unrecognized terms** (warning): Bolded terms that look like product names but aren't in `terminology.md`. Flags candidates for glossary addition — not errors, just suggestions.
- **Warp Factories naming**: A bare capitalized "Factory" used as a proper noun. "Warp Factories" is the product and is written in full; an individual "factory" is lowercase. Sentence-, heading-, bullet-, quote-, and cell-initial capitals are positional and stay, as do frontmatter titles and labels, the shipped feature name "Factory MCP", and verbatim UI strings such as **Factory name** and **Add your Factory to your team**. Regression cases live in `test_factory_proper_noun.py`.
- **Hardcoded product name strings**: Product name strings that have a corresponding key in `src/data/vars.ts` but appear as literal text rather than variable syntax. Reports instances of known strings like "Oz CLI", "Oz web app", "oz.warp.dev", "Oz dashboard", "Oz run" (any value currently in `src/data/vars.ts`) in body prose and frontmatter. These are flagged as `⚠️ [IMPORTANT]` in PR context and reported (not auto-fixed) — they should use `{VARS.KEY}` in prose and `{{TOKEN}}` in frontmatter.

## Auto-fix behavior
Expand All @@ -72,6 +73,16 @@ When run with `--fix`:

This skill checks broader formatting and terminology. The `validate_ui_refs` skill validates UI paths and Command Palette names against the warp-internal codebase. They complement each other with no overlap. Both can run in scheduled cloud agent workflows.

## Tests

Two checks have regression suites, because both are narrow rules where the hard
part is not firing on legitimate text. Run them after touching either check:

```bash
python3 .agents/skills/style_lint/test_platform_determiner.py
python3 .agents/skills/style_lint/test_factory_proper_noun.py
```

## Dependencies

Requires Python 3.7+. Optional: `requests` (for Slack notifications), `gh` CLI (for PR creation).
Expand Down
96 changes: 96 additions & 0 deletions .agents/skills/style_lint/style_lint.py
Original file line number Diff line number Diff line change
Expand Up @@ -1163,6 +1163,101 @@ def check_platform_determiner(lines: List[str], filepath: str) -> List[Issue]:
return issues


# "Warp Factories" is the product; a "factory" is an instance. A bare
# capitalized "Factory" is never a proper noun, with two classes of exception:
# the feature's own name (Factory MCP) and verbatim product strings the docs
# quote from the app. Both are matched on the word that FOLLOWS "Factory".
FACTORY_ALLOWED_NEXT_WORDS = {
# Feature name, shipped as such: the server registers as `warp-factory`.
"MCP",
# Verbatim UI strings. Changing these would make the docs disagree with the
# screen, so they are quoted as-is until the app copy changes.
"name", # **Factory name** field in the setup wizard
"definition", # **Factory definition** sidebar tab
"integrations", # **Factory integrations** section in Settings
"running", # "Factory running!" on the setup summary screen
}
# Whole phrases that are correct despite containing a bare "Factory": verbatim
# UI strings the docs quote, and references to unrelated products that happen to
# be named Factory.
FACTORY_ALLOWED_PHRASES = (
"Add your Factory to your team", # verbatim setup wizard heading
"Factory's CLI coding agent", # Factory.ai, the company behind Droid
)
FACTORY_BARE = re.compile(r"\bFactory\b")
# Markup that can sit between the start of a sentence and the word itself:
# heading hashes, list bullets, blockquotes, emphasis, link text, quotes, and
# table cell pipes. Stripped before deciding whether the position is initial.
FACTORY_LEADING_MARKUP = re.compile(r"[\s*_\[\(\"'|>#\-\u2014\u2013]+$")


def check_factory_proper_noun(lines: List[str], filepath: str) -> List[Issue]:
"""Flag a bare capitalized "Factory" used as a proper noun.

The rule works like GitHub Actions: "Warp Factories" is the product and is
always written in full, an individual "factory" is a lowercase common noun,
and there is no product called "Factory". See AGENTS.md -> Warp Factories
terminology.

Quiet by construction, because most capitalized "Factory" occurrences are
legitimate:
* "Warp Factories" and "Warp Factory" -- the product name
* sentence-, heading-, bullet-, link-, quote-, and cell-initial position,
where the capital is positional rather than a proper noun
* fenced code blocks, inline code, link targets, and HTML attributes
* frontmatter, whose titles and sidebar labels are headline-style
* the exceptions in FACTORY_ALLOWED_NEXT_WORDS and
FACTORY_ALLOWED_PHRASES
"""
issues = []
in_code_block = False
in_frontmatter = False
for i, line in enumerate(lines, 1):
stripped = line.strip()
if i == 1 and stripped == "---":
in_frontmatter = True
continue
if in_frontmatter:
if stripped == "---":
in_frontmatter = False
continue
if stripped.startswith("```"):
in_code_block = not in_code_block
continue
if in_code_block or "Factory" not in line:
continue
if any(phrase in line for phrase in FACTORY_ALLOWED_PHRASES):
continue
# Strip inline code, link targets, and HTML/JSX attributes: a slug like
# `/factories/factory-as-code/` or an `alt="..."` value is not prose.
prose = re.sub(r"`[^`]*`", "", line)
prose = re.sub(r"\]\([^)]*\)", "]", prose)
prose = re.sub(r'\w+="[^"]*"', "", prose)
for m in FACTORY_BARE.finditer(prose):
before = prose[:m.start()]
after = prose[m.end():]
if before.rstrip().endswith("Warp"):

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.

⚠️ [IMPORTANT] This skip lets Warp Factory through, but the new terminology rule says the product is only Warp Factories and an instance is lowercase. FACTORY_BARE doesn't match Factories, so this exception only hides the banned singular form; remove it and let the existing Factory MCP exception handle the shipped feature name.

continue # "Warp Factories" / "Warp Factory"
# Strip the markup between the sentence start and the word, then ask
# whether anything is left. Nothing left means the capital is
# positional; a preceding clause means it is being used as a name.
prefix = FACTORY_LEADING_MARKUP.sub("", before)
if not prefix or prefix.endswith((".", "!", "?", ":", "|", "—")):
continue
nxt = re.match(r"\s+(\w+)", after)
if nxt and nxt.group(1) in FACTORY_ALLOWED_NEXT_WORDS:
continue
issues.append(Issue(
filepath, i, "factory-proper-noun",
'Bare "Factory" used as a proper noun. "Warp Factories" is the '
'product and is written in full; an individual factory is '
'lowercase. Write "factory" (or "Warp Factories" if you mean '
"the product).",
"warning",
))
return issues


# Cache glossary terms once at module level
_glossary_cache: Optional[set] = None

Expand Down Expand Up @@ -1193,6 +1288,7 @@ def run_all_checks(filepath: Path) -> List[Issue]:
issues.extend(check_deprecated_terms(lines, str(filepath)))
issues.extend(check_hardcoded_vars(lines, str(filepath)))
issues.extend(check_platform_determiner(lines, str(filepath)))
issues.extend(check_factory_proper_noun(lines, str(filepath)))
issues.extend(check_unrecognized_terms(lines, str(filepath), _get_glossary()))
return issues

Expand Down
100 changes: 100 additions & 0 deletions .agents/skills/style_lint/test_factory_proper_noun.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
#!/usr/bin/env python3
"""Regression cases for check_factory_proper_noun.

Run from the repo root:
python3 .agents/skills/style_lint/test_factory_proper_noun.py

The rule is narrow: "Warp Factories" is the product, an individual "factory" is
a lowercase common noun, and a bare capitalized "Factory" is never a proper
noun. Almost all of the difficulty is in NOT firing, because a capital F is
usually positional rather than a name -- headings, sidebar labels, bullets,
table cells, quoted terms, and link text all start with one legitimately.

The first draft of this check produced 9 hits across the docs and 8 of them
were wrong: heading-initial ("## Factory-definition pull request checks"),
list-initial link text ("* [Factory dashboard](...)"), frontmatter labels, a
quoted term at the start of a sentence, a verbatim UI string ("Add your Factory
to your team"), and a reference to Factory.ai, the company behind Droid. Each
of those is a case below. If you touch the check, run this first.
"""
import importlib.util
import pathlib
import sys

HERE = pathlib.Path(__file__).parent
spec = importlib.util.spec_from_file_location("style_lint", HERE / "style_lint.py")
style_lint = importlib.util.module_from_spec(spec)
spec.loader.exec_module(style_lint)

CASES = [
# (text, should_flag, description)
# --- genuine proper-noun uses ---
("See [Factory agents](/factories/factory-agents/) for the roles.", True,
"mid-sentence link text"),
("Every Factory gets its own Slack app.", True,
"mid-sentence, standing in for the product"),
("Runs started by the Factory are tracked.", True,
"definite article plus a capital"),
("Review the Factory metrics before deciding.", True,
"mid-sentence attributive use of the banned form"),
# --- the product name, written correctly ---
("Warp Factories is in Early Access.", False, "the product name"),
("Connect Warp Factories to your repository.", False, "product name mid-sentence"),
# --- positional capitals ---
("## Factory-definition pull request checks", False, "heading-initial"),
("### Factory agents", False, "subheading-initial"),
("* [Factory dashboard](/factories/factory-dashboard/) - the surface.", False,
"list-initial link text"),
("Factory setup doesn't choose models for you.", False, "sentence-initial"),
('"Factory dashboard" names the whole surface.', False, "quoted term, sentence-initial"),
("| **Factory definition** | The definition files |", False, "table-cell-initial"),
("The tab is read-only. Factory owners can still edit it.", False,
"initial after a sentence boundary"),
# --- sanctioned exceptions ---
("Send work through the Factory MCP.", False, "Factory MCP is the shipped feature name"),
("Enter a **Factory name**, such as `Payments`.", False, "verbatim UI field label"),
("The **Factory definition** tab lists the files.", False, "verbatim UI tab label"),
("1. In factory setup, go to **Add your Factory to your team**.", False,
"verbatim UI string, allowlisted as a phrase"),
("* **Droid** — Factory's CLI coding agent", False,
"Factory.ai, an unrelated company"),
# --- non-prose ---
("Fetch `/api/v1/Factory/source` for the definition.", False, "inline code"),
('<img alt="Factory settings page" src="x.png" />', False, "HTML attribute"),
]

FRONTMATTER_CASE = (
['---', 'title: Factory dashboard', 'sidebar:', ' label: "Factory agents"', '---',
'The factory dashboard is the web app for one factory.'],
False,
"frontmatter titles and labels are headline-style",
)


def main() -> int:
failures = 0
for text, should_flag, description in CASES:
flagged = bool(style_lint.check_factory_proper_noun(text.split("\n"), "test.mdx"))
ok = flagged == should_flag
if not ok:
failures += 1
print(f" [{'PASS' if ok else 'FAIL'}] {description:<48} flagged={flagged}")

lines, should_flag, description = FRONTMATTER_CASE
flagged = bool(style_lint.check_factory_proper_noun(lines, "test.mdx"))
ok = flagged == should_flag
if not ok:
failures += 1
print(f" [{'PASS' if ok else 'FAIL'}] {description:<48} flagged={flagged}")

total = len(CASES) + 1
print()
if failures:
print(f"{failures} of {total} cases regressed.")
return 1
print(f"All {total} cases behave correctly.")
return 0


if __name__ == "__main__":
sys.exit(main())
Loading
Loading