Getting it into your agent
One page per mod, every tool's command on it. A separate URL per tool would split the same page into five that compete with each other.
npx agentmods add rules/jrpribs/smarterstarter/500-angular-pipesgit clone --depth 1 https://github.com/JrPribs/SmarterStarterWrote this? Show the measurements
A badge with what this costs and how it scanned, read live from this page, so it follows the numbers instead of freezing them. Markdown for a README, HTML for a documentation site or a project page.
[](https://agentmods.dev/rules/jrpribs/smarterstarter/500-angular-pipes)<a href="https://agentmods.dev/rules/jrpribs/smarterstarter/500-angular-pipes"><img src="https://agentmods.dev/badge/rules/jrpribs/smarterstarter/500-angular-pipes.svg" alt="Measured on agentmods" height="20"></a>What it costs to keep this loaded
Counted locally with the o200k_base tokenizer, which is exact for GPT models; Claude uses its own tokenizer and its counts differ. Treat this as one consistent yardstick across the catalogue rather than a bill. Prices are per million input tokens.
| Model | Per session | Once invoked |
|---|---|---|
| Fable 5 | $0.00002 | $0.01646 |
| Opus 5 | $0.00001 | $0.00823 |
| Sonnet 5 | $0.00000 | $0.00329 |
| Haiku 4.5 | $0.00000 | $0.00165 |
Grade A, and why
500-angular-pipes scanned grade A with 0 findings against 26 rules in 11 categories — prompt injection, anti-refusal, data exfiltration, privilege escalation, supply chain, agent snooping, system-prompt leakage, SSRF and excessive agency — measured 4d ago.
A static scan of the body, not an audit. Every finding is printed with the line that produced it so you can judge whether it matters here. A mod is markdown that instructs an agent; that is exactly why what it instructs is worth reading.
Nothing flagged
None of the 26 patterns this scan looks for appear in this file: no shell pipes, no recursive deletes, no credential paths, no hidden text, no instruction-override or anti-refusal phrasing, no agent-config snooping. That is not a guarantee, it is the absence of the things that are checkable.
How it starts
The opening of the file, as written. The whole thing — 246 lines — stays where its author put it; the contents beside it link to each section on GitHub.
Angular Pipes Best Practices
- Standalone Pipes: Create pipes as standalone to avoid NgModule configuration.
@Pipe({
name: 'truncate',
standalone: true
})
export class TruncatePipe implements PipeTransform {
transform(value: string, limit: number = 100, completeWords: boolean = false, ellipsis: string = '...'): string {
if (!value) return '';
if (value.length <= limit) return value;
if (completeWords) {
limit = value.substring(0, limit).lastIndexOf(' ');
}
return value.substring(0, limit) + ellipsis;
}
}
- Pure Pipes: Keep pipes pure by default. Only use impure pipes when absolutely necessary.
// Pure pipe (default)
@Pipe({
name: 'sort',
standalone: true
})
export class SortPipe implements PipeTransform {
transform<T>(array: T[], property: keyof T): T[] {
if (!array || !property) return array;
return [...array].sort((a, b) => {
const aValue = a[property];
const bValue = b[property];
return aValue < bValue ? -1 : aValue > bValue ? 1 : 0;
});
}
}
// Impure pipe (only when needed)
@Pipe({
name: 'filterBy',
standalone: true,
pure: false // Impure pipe, will run on every change detection cycle
})
export class FilterPipe implements PipeTransform {
transform<T>(items: T[], property: keyof T, value: any): T[] {
if (!items || !property) return items;
return items.filter(item => item[property] === value);
}
}
- Pipe Naming: Use lowerCamelCase for pipe names and use a descriptive name that indicates the pipe's function.
// Good pipe names
name: 'truncate'
name: 'fileSize'
name: 'dateTimeFormat'
// Avoid generic names
name: 'format' // Too generic
name: 'convert' // Unclear purpose
- Type Safety: Use TypeScript generics to make pipes type-safe.
@Pipe({
name: 'pluck',
standalone: true
})
export class PluckPipe implements PipeTransform {
transform<T, K extends keyof T>(input: T[], key: K): T[K][] {
if (!input || !Array.isArray(input) || !key) return [];
return input.map(value => value[key]);
}
}
- Pipe Performance: Be mindful of performance, especially with large data sets. Consider caching results or using memoization for expensive transformations.
@Pipe({
name: 'expensiveTransform',
standalone: true
})
export class ExpensiveTransformPipe implements PipeTransform {
private lastValue: any;
private lastResult: any;
transform(value: any): any {
// Simple memoization to avoid recalculating for the same input
if (value === this.lastValue) {
return this.lastResult;
}
this.lastValue = value;
this.lastResult = this.performExpensiveCalculation(value);
return this.lastResult;
}
private performExpensiveCalculation(value: any): any {
// Complex transformation logic here
return value;
}
}
- Chaining Pipes: Design pipes that can be easily chained with other pipes. Focus on a single transformation per pipe.
<!-- Good pipe chaining example in template -->
{{ user.created | date:'short' | uppercase }}
- Documentation: Document pipe parameters clearly using JSDoc so that developers can easily understand how to use them.
/**
* Truncates text to a specified length and adds an ellipsis.
*
* @param value - The string to truncate
* @param limit - Maximum string length (default: 100)
* @param completeWords - Whether to keep complete words (default: false)
* @param ellipsis - String to add at the end (default: '...')
*
* @example
* {{ 'This is a long text' | truncate:10:true }}
* Output: "This is..."
*
* @return Truncated string
*/
@Pipe({
name: 'truncate',
standalone: true
})
export class TruncatePipe implements PipeTransform {
// Implementation
}
- Testing Pipes: Create thorough unit tests for pipes, testing various input combinations and edge cases.
describe('TruncatePipe', () => {
let pipe: TruncatePipe;
beforeEach(() => {
pipe = new TruncatePipe();
});
it('should truncate text if over specified limit', () => {
expect(pipe.transform('This is a test string', 10)).toBe('This is a ...');
});
it('should not truncate text if under specified limit', () => {
expect(pipe.transform('Short', 10)).toBe('Short');
});
it('should respect the completeWords flag', () => {
expect(pipe.transform('This is a test string', 10, true)).toBe('This is ...');
});
it('should use custom ellipsis', () => {
expect(pipe.transform('This is a test string', 10, false, '***')).toBe('This is a ***');
});
it('should handle null or undefined values', () => {
expect(pipe.transform(null as any)).toBe('');
expect(pipe.transform(undefined as any)).toBe('');
});
});
What this file has done since we first saw it
Hashed on every crawl. A supply-chain change to an agent config is a question of when, not whether, so the history is kept rather than the latest state alone.
- 4d ago First seen · 246 lines · 2 tokens per session scan A 3dbdc2172679
500-angular-pipes is a cursor rule published in the GitHub repository JrPribs/SmarterStarter (2 stars, last pushed 1y ago), licensed MIT. It adds 2 tokens to every session and 1,646 once invoked, about $0.0000 per session on Opus 5. A static security scan graded it A with 0 findings. No closer match exists in the catalogue, so it is treated as the original; first seen 2026-08-31.
Other cursor rules, from other repositories
angular-20
This rule provides comprehensive best practices and coding standards for Angular development, focusing on modern TypeScript, standalone components, signals, and performance optimizations.
dev-standard
Apache Superset development standards and guidelines for Cursor IDE.
cli-error-handling
CLI command error handling patterns.
prefer-direct-imports-over-module-mocks
Prefer extracting a testable core over vi.mock / vi.resetModules when unit tests need to reach production logic entangled with config, env, or singletons.
control-plane-descriptors
Control plane descriptor and instance implementation patterns.
family-instance-domain-actions
Family instance domain action implementation patterns.