diff --git a/KNOWLEDGE_BASE.md b/KNOWLEDGE_BASE.md
index 4012c6e8bb..67bfec0230 100644
--- a/KNOWLEDGE_BASE.md
+++ b/KNOWLEDGE_BASE.md
@@ -204,6 +204,8 @@ Sources: [log types](app/Enums/Log.php), [log queries](app/Queries/LogQueries),
Open search with **⌘/Ctrl+K** or **/**. Developer search finds people by name or GitHub username, and lists the GitHub organizations that already have a page on /dev/null below them, by name or handle. Commit search, also available at `/search`, finds posts by meaning rather than requiring an exact phrase: describe the topic you want to read about. Commit queries must contain at least three characters and at most 100, and cover replies as well as top-level commits. An AI relevance check filters the nearest matches, so a search can return fewer results than asked. Results respect visibility, mutes, and blocks; semantic matching does not guarantee that every relevant commit will be returned. Guests can search developers and organizations; searching commits, and `/search`, need sign-in, since each commit search pays for AI. Commit search is limited to 15 searches a minute per person.
+The search results page opens on **Most relevant**. **Latest** shows only matches from the past seven days, newest first, from the same result set. Switching tabs is instant and does not run another search; Latest does not look for additional recent matches outside that set.
+
Signed-in users see their three most recent distinct searches above the suggested searches, newest first. Repeating a search moves it to the top; adding a fourth discards the oldest from storage, not just from the display. Recent searches stay in this browser, scoped to the signed-in account, and do not sync to other devices or create server-side history. They are cleared on sign-out or account deletion in that browser. Guests do not retain recent searches.
The public search searches developers, organizations, and commits, not this knowledge-base file. Feature documentation is available to the internal knowledge-base retriever once indexed; there is no public knowledge-base search endpoint yet.
diff --git a/resources/js/lib/commit-search-results.ts b/resources/js/lib/commit-search-results.ts
new file mode 100644
index 0000000000..883ab574eb
--- /dev/null
+++ b/resources/js/lib/commit-search-results.ts
@@ -0,0 +1,25 @@
+import type { Commit } from '@/types';
+
+export class CommitSearchResults {
+ term: string;
+ commits: Commit[];
+
+ constructor(term: string, commits: Commit[]) {
+ this.term = term;
+ this.commits = commits;
+ }
+
+ latest(): CommitSearchResults {
+ const since = Date.now() - 7 * 24 * 60 * 60 * 1000;
+
+ return new CommitSearchResults(
+ this.term,
+ this.commits
+ .filter((commit) => Date.parse(commit.created_at) >= since)
+ .sort(
+ (a, b) =>
+ Date.parse(b.created_at) - Date.parse(a.created_at),
+ ),
+ );
+ }
+}
diff --git a/resources/js/pages/search/index.tsx b/resources/js/pages/search/index.tsx
index d4e82683b0..a10e53feb8 100644
--- a/resources/js/pages/search/index.tsx
+++ b/resources/js/pages/search/index.tsx
@@ -1,3 +1,4 @@
+import { Tab, TabGroup, TabList, TabPanel, TabPanels } from '@headlessui/react';
import { Head, router, usePage } from '@inertiajs/react';
import { ArrowRight, History, Search, Sparkles, X } from 'lucide-react';
import type { FormEvent } from 'react';
@@ -7,11 +8,14 @@ import { SearchResults } from '@/components/commit-search-results';
import { rememberSearch, useRecentSearches } from '@/hooks/use-recent-searches';
import AppLayout from '@/layouts/app-layout';
import { searchCommits, suggestedQueries } from '@/lib/commit-search';
-import type { Commit } from '@/types';
+import { CommitSearchResults } from '@/lib/commit-search-results';
const skeletonDelay = 300;
-type Results = { term: string; commits: Commit[] };
+type Results = {
+ relevant: CommitSearchResults;
+ latest: CommitSearchResults;
+};
export default function Index({ query }: { query: string }) {
const userId = usePage().props.auth.user?.id ?? null;
@@ -85,7 +89,43 @@ export default function Index({ query }: { query: string }) {
{query !== '' && (
-
+
+
+ {['Most relevant', 'Latest'].map((title) => (
+
+
+ {title}
+
+
+
+ ))}
+
+
+
+
+
+
+
+
+
+
)}
{recentSearches.length > 0 && (
@@ -114,10 +154,14 @@ function useCommitSearch(query: string) {
const timeout = setTimeout(() => setIsWaiting(true), skeletonDelay);
searchCommits(query, undefined, controller.signal)
- .then((commits) => setResults({ term: query, commits }))
+ .then((commits) => {
+ const relevant = new CommitSearchResults(query, commits);
+ setResults({ relevant, latest: relevant.latest() });
+ })
.catch(() => {
if (!controller.signal.aborted) {
- setResults({ term: query, commits: [] });
+ const relevant = new CommitSearchResults(query, []);
+ setResults({ relevant, latest: relevant.latest() });
}
})
.finally(() => {
diff --git a/tests/Unit/CommitSearchResults.test.ts b/tests/Unit/CommitSearchResults.test.ts
new file mode 100644
index 0000000000..1df88b4b67
--- /dev/null
+++ b/tests/Unit/CommitSearchResults.test.ts
@@ -0,0 +1,42 @@
+import assert from 'node:assert/strict';
+import { test } from 'node:test';
+import { CommitSearchResults } from '../../resources/js/lib/commit-search-results.ts';
+import type { Commit } from '../../resources/js/types';
+
+await test('latest keeps the past week newest first without changing relevance order', (context) => {
+ context.mock.method(Date, 'now', () => Date.parse('2026-11-03T12:00:00Z'));
+ const commits = [
+ { id: 'old', created_at: '2026-10-27T11:59:59.999Z' },
+ { id: 'boundary', created_at: '2026-10-27T12:00:00Z' },
+ { id: 'recent', created_at: '2026-11-02T13:00:00+01:00' },
+ { id: 'newest', created_at: '2026-11-03T11:00:00Z' },
+ { id: 'middle', created_at: '2026-10-30T12:00:00Z' },
+ ] as Commit[];
+ const relevant = new CommitSearchResults('testing strategies', commits);
+
+ const latest = relevant.latest();
+
+ assert.equal(latest.term, 'testing strategies');
+ assert.deepEqual(
+ latest.commits.map((commit) => commit.id),
+ ['newest', 'recent', 'middle', 'boundary'],
+ );
+ assert.deepEqual(
+ relevant.commits.map((commit) => commit.id),
+ ['old', 'boundary', 'recent', 'newest', 'middle'],
+ );
+});
+
+await test('latest is empty when there are no recent matches', (context) => {
+ context.mock.method(Date, 'now', () => Date.parse('2026-11-03T12:00:00Z'));
+
+ for (const commits of [
+ [],
+ [{ id: 'old', created_at: '2026-10-20T12:00:00Z' }] as Commit[],
+ ]) {
+ assert.deepEqual(
+ new CommitSearchResults('an idea', commits).latest().commits,
+ [],
+ );
+ }
+});