job_ops-mcp 0.3.0

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.
Files changed (116) hide show
  1. package/.env.example +33 -0
  2. package/LICENSE +21 -0
  3. package/README.md +400 -0
  4. package/config/profile.example.yml +67 -0
  5. package/cv.example.md +53 -0
  6. package/dist/cli.js +385 -0
  7. package/dist/cli.js.map +1 -0
  8. package/dist/config.js +63 -0
  9. package/dist/config.js.map +1 -0
  10. package/dist/core/browser.js +27 -0
  11. package/dist/core/browser.js.map +1 -0
  12. package/dist/core/content_hash.js +11 -0
  13. package/dist/core/content_hash.js.map +1 -0
  14. package/dist/core/csv.js +107 -0
  15. package/dist/core/csv.js.map +1 -0
  16. package/dist/core/cv_parse.js +201 -0
  17. package/dist/core/cv_parse.js.map +1 -0
  18. package/dist/core/html.js +10 -0
  19. package/dist/core/html.js.map +1 -0
  20. package/dist/core/jd_normalize.js +99 -0
  21. package/dist/core/jd_normalize.js.map +1 -0
  22. package/dist/core/jobs.js +106 -0
  23. package/dist/core/jobs.js.map +1 -0
  24. package/dist/core/llm.js +227 -0
  25. package/dist/core/llm.js.map +1 -0
  26. package/dist/core/modes.js +55 -0
  27. package/dist/core/modes.js.map +1 -0
  28. package/dist/core/outreach_safety.js +77 -0
  29. package/dist/core/outreach_safety.js.map +1 -0
  30. package/dist/core/profile.js +88 -0
  31. package/dist/core/profile.js.map +1 -0
  32. package/dist/core/providers/amazon.js +36 -0
  33. package/dist/core/providers/amazon.js.map +1 -0
  34. package/dist/core/providers/ashby.js +31 -0
  35. package/dist/core/providers/ashby.js.map +1 -0
  36. package/dist/core/providers/google.js +46 -0
  37. package/dist/core/providers/google.js.map +1 -0
  38. package/dist/core/providers/greenhouse.js +55 -0
  39. package/dist/core/providers/greenhouse.js.map +1 -0
  40. package/dist/core/providers/http.js +36 -0
  41. package/dist/core/providers/http.js.map +1 -0
  42. package/dist/core/providers/index.js +53 -0
  43. package/dist/core/providers/index.js.map +1 -0
  44. package/dist/core/providers/lever.js +32 -0
  45. package/dist/core/providers/lever.js.map +1 -0
  46. package/dist/core/providers/playwright_generic.js +53 -0
  47. package/dist/core/providers/playwright_generic.js.map +1 -0
  48. package/dist/core/providers/types.js +2 -0
  49. package/dist/core/providers/types.js.map +1 -0
  50. package/dist/core/providers/workday.js +44 -0
  51. package/dist/core/providers/workday.js.map +1 -0
  52. package/dist/core/render.js +253 -0
  53. package/dist/core/render.js.map +1 -0
  54. package/dist/core/reports.js +257 -0
  55. package/dist/core/reports.js.map +1 -0
  56. package/dist/core/resources.js +40 -0
  57. package/dist/core/resources.js.map +1 -0
  58. package/dist/core/scan_engine.js +164 -0
  59. package/dist/core/scan_engine.js.map +1 -0
  60. package/dist/core/scheduler.js +117 -0
  61. package/dist/core/scheduler.js.map +1 -0
  62. package/dist/db.js +60 -0
  63. package/dist/db.js.map +1 -0
  64. package/dist/http/app.js +35 -0
  65. package/dist/http/app.js.map +1 -0
  66. package/dist/http/dashboard.js +131 -0
  67. package/dist/http/dashboard.js.map +1 -0
  68. package/dist/mcp/define.js +35 -0
  69. package/dist/mcp/define.js.map +1 -0
  70. package/dist/mcp/server.js +103 -0
  71. package/dist/mcp/server.js.map +1 -0
  72. package/dist/mcp/tools/apply_prefill.js +167 -0
  73. package/dist/mcp/tools/apply_prefill.js.map +1 -0
  74. package/dist/mcp/tools/batch_evaluate.js +143 -0
  75. package/dist/mcp/tools/batch_evaluate.js.map +1 -0
  76. package/dist/mcp/tools/evaluate_job.js +181 -0
  77. package/dist/mcp/tools/evaluate_job.js.map +1 -0
  78. package/dist/mcp/tools/generate_materials.js +126 -0
  79. package/dist/mcp/tools/generate_materials.js.map +1 -0
  80. package/dist/mcp/tools/get_report.js +24 -0
  81. package/dist/mcp/tools/get_report.js.map +1 -0
  82. package/dist/mcp/tools/ops.js +321 -0
  83. package/dist/mcp/tools/ops.js.map +1 -0
  84. package/dist/mcp/tools/outreach.js +481 -0
  85. package/dist/mcp/tools/outreach.js.map +1 -0
  86. package/dist/mcp/tools/render_pdf.js +27 -0
  87. package/dist/mcp/tools/render_pdf.js.map +1 -0
  88. package/dist/mcp/tools/scan_portals.js +35 -0
  89. package/dist/mcp/tools/scan_portals.js.map +1 -0
  90. package/dist/mcp/tools/scheduler.js +32 -0
  91. package/dist/mcp/tools/scheduler.js.map +1 -0
  92. package/dist/mcp/tools/stories.js +172 -0
  93. package/dist/mcp/tools/stories.js.map +1 -0
  94. package/dist/mcp/tools/tracker.js +183 -0
  95. package/dist/mcp/tools/tracker.js.map +1 -0
  96. package/dist/mcp/tools/visa.js +219 -0
  97. package/dist/mcp/tools/visa.js.map +1 -0
  98. package/dist/migrations/001_initial.sql +505 -0
  99. package/dist/migrations/002_llm_and_digest.sql +42 -0
  100. package/dist/server.js +55 -0
  101. package/dist/server.js.map +1 -0
  102. package/fonts/dm-sans-latin-ext.woff2 +0 -0
  103. package/fonts/dm-sans-latin.woff2 +0 -0
  104. package/fonts/space-grotesk-latin-ext.woff2 +0 -0
  105. package/fonts/space-grotesk-latin.woff2 +0 -0
  106. package/modes/career_packet.md +91 -0
  107. package/modes/negotiation_playbook.md +64 -0
  108. package/modes/outreach_tone.md +80 -0
  109. package/modes/report_format.md +83 -0
  110. package/modes/rubric.md +119 -0
  111. package/modes/tailoring_rules.md +102 -0
  112. package/package.json +67 -0
  113. package/portals.example.yml +95 -0
  114. package/templates/cover-template.html +64 -0
  115. package/templates/cv-template.html +421 -0
  116. package/templates/cv-template.tex +123 -0
@@ -0,0 +1,95 @@
1
+ # job_ops-mcp portals configuration.
2
+ #
3
+ # Copy to `portals.yml` (or let `npx job_ops-mcp init` do it) and fill in the companies
4
+ # whose careers boards you want to scan. Three provider auto-detectors run against
5
+ # `careers_url`:
6
+ #
7
+ # - Greenhouse → URLs containing `job-boards.greenhouse.io/<slug>` (or set `greenhouse_slug`)
8
+ # - Ashby → URLs containing `jobs.ashbyhq.com/<slug>` (or set `ashby_slug`)
9
+ # - Lever → URLs containing `jobs.lever.co/<slug>` (or set `lever_slug`)
10
+ #
11
+ # Plus explicit-opt-in providers:
12
+ # - Workday → set `workday_url: https://<tenant>.wd<N>.myworkdayjobs.com/<site>`
13
+ # - Amazon → set `provider: amazon` (uses the public amazon.jobs JSON endpoint)
14
+ # - Google → set `provider: google` (Playwright; selectors break occasionally)
15
+ # - Generic Playwright → set `provider: playwright_generic` + selectors block
16
+ #
17
+ # Title / location filters apply across every provider. They're substring-matched,
18
+ # case-insensitive, OR-ed within positive lists, AND-ed across lists. Empty list = pass.
19
+
20
+ title_filter:
21
+ positive:
22
+ - "engineer"
23
+ - "ml"
24
+ - "ai"
25
+ - "product manager"
26
+ - "data"
27
+ negative:
28
+ - "intern"
29
+ - "manager of engineering"
30
+ - "principal scientist"
31
+
32
+ location_filter:
33
+ # Allow only roles tagged with one of these (substring match).
34
+ allow:
35
+ - "remote"
36
+ - "united states"
37
+ - "san francisco"
38
+ - "new york"
39
+ # Auto-reject these regardless of `allow`.
40
+ block:
41
+ - "on-site only"
42
+ - "5 days in office"
43
+ # `always_allow` wins over `block` — useful for multi-location postings like
44
+ # "Remote, US or EU" where you'd otherwise lose the US slot to the EU block.
45
+ always_allow:
46
+ - "remote, us"
47
+
48
+ tracked_companies:
49
+ # Greenhouse — auto-detected from careers_url.
50
+ - name: "<Company A>"
51
+ careers_url: "https://job-boards.greenhouse.io/<slug>"
52
+ priority: 1
53
+ enabled: true
54
+
55
+ # Ashby — auto-detected.
56
+ - name: "<Company B>"
57
+ careers_url: "https://jobs.ashbyhq.com/<slug>"
58
+ priority: 1
59
+ enabled: true
60
+
61
+ # Lever — auto-detected.
62
+ - name: "<Company C>"
63
+ careers_url: "https://jobs.lever.co/<slug>"
64
+ priority: 2
65
+ enabled: true
66
+
67
+ # Workday — explicit URL.
68
+ - name: "<Company D>"
69
+ workday_url: "https://<tenant>.wd5.myworkdayjobs.com/<site>"
70
+ priority: 2
71
+ enabled: true
72
+
73
+ # Amazon — explicit provider, with an optional team filter.
74
+ # - name: "Amazon AGI"
75
+ # provider: "amazon"
76
+ # amazon_base_query: "AGI"
77
+ # enabled: false
78
+
79
+ # Google — Playwright-based scraper.
80
+ # - name: "Google"
81
+ # provider: "google"
82
+ # google_query: "product manager"
83
+ # google_loc: "United States"
84
+ # enabled: false
85
+
86
+ # Generic Playwright fallback for closed boards.
87
+ # - name: "<Closed-board company>"
88
+ # provider: "playwright_generic"
89
+ # careers_url: "https://example.com/careers"
90
+ # selectors:
91
+ # item: "a.job-card"
92
+ # title: ".job-title"
93
+ # location: ".job-location"
94
+ # wait_for: ".jobs-loaded"
95
+ # enabled: false
@@ -0,0 +1,64 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <title>{{NAME}} — Cover Letter</title>
6
+ <style>
7
+ @font-face {
8
+ font-family: 'DM Sans';
9
+ src: url('./fonts/dm-sans-latin.woff2') format('woff2');
10
+ font-weight: 100 1000;
11
+ font-style: normal;
12
+ font-display: swap;
13
+ }
14
+ body {
15
+ font-family: 'DM Sans', sans-serif;
16
+ font-size: 11.5px;
17
+ line-height: 1.6;
18
+ color: #1a1a2e;
19
+ background: #fff;
20
+ margin: 0;
21
+ padding: 0;
22
+ }
23
+ .page { max-width: 7.4in; margin: 0 auto; padding: 0; }
24
+ .header { margin-bottom: 22px; }
25
+ .header h1 {
26
+ font-family: 'DM Sans', sans-serif;
27
+ font-size: 22px;
28
+ font-weight: 700;
29
+ color: #1a1a2e;
30
+ margin: 0 0 4px 0;
31
+ }
32
+ .header-gradient {
33
+ height: 2px;
34
+ background: linear-gradient(to right, hsl(187, 74%, 32%), hsl(270, 70%, 45%));
35
+ border-radius: 1px;
36
+ margin-bottom: 8px;
37
+ }
38
+ .contact { color: #555; font-size: 10.5px; }
39
+ .meta { color: #555; font-size: 10.5px; margin-bottom: 18px; }
40
+ .salutation { margin-bottom: 12px; }
41
+ .body p { margin: 0 0 10px 0; }
42
+ .closing { margin-top: 14px; }
43
+ .signature { margin-top: 22px; font-weight: 600; }
44
+ @media print { .page { padding: 0; } }
45
+ </style>
46
+ </head>
47
+ <body>
48
+ <div class="page">
49
+ <div class="header">
50
+ <h1>{{NAME}}</h1>
51
+ <div class="header-gradient"></div>
52
+ <div class="contact">{{CONTACT_LINE}}</div>
53
+ </div>
54
+ <div class="meta">
55
+ <div>{{DATE}}</div>
56
+ <div>{{COMPANY}}{{COMPANY_LOCATION}}</div>
57
+ </div>
58
+ <div class="salutation">Dear Hiring Manager,</div>
59
+ <div class="body">{{BODY}}</div>
60
+ <div class="closing">Best regards,</div>
61
+ <div class="signature">{{NAME}}</div>
62
+ </div>
63
+ </body>
64
+ </html>
@@ -0,0 +1,421 @@
1
+ <!DOCTYPE html>
2
+ <html lang="{{LANG}}">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>{{NAME}} — CV</title>
7
+ <style>
8
+ @font-face {
9
+ font-family: 'Space Grotesk';
10
+ src: url('./fonts/space-grotesk-latin.woff2') format('woff2');
11
+ font-weight: 300 700;
12
+ font-style: normal;
13
+ font-display: swap;
14
+ unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
15
+ }
16
+
17
+ @font-face {
18
+ font-family: 'Space Grotesk';
19
+ src: url('./fonts/space-grotesk-latin-ext.woff2') format('woff2');
20
+ font-weight: 300 700;
21
+ font-style: normal;
22
+ font-display: swap;
23
+ unicode-range: U+0100-02AF, U+0304, U+0308, U+0329, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
24
+ }
25
+
26
+ @font-face {
27
+ font-family: 'DM Sans';
28
+ src: url('./fonts/dm-sans-latin.woff2') format('woff2');
29
+ font-weight: 100 1000;
30
+ font-style: normal;
31
+ font-display: swap;
32
+ unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
33
+ }
34
+
35
+ @font-face {
36
+ font-family: 'DM Sans';
37
+ src: url('./fonts/dm-sans-latin-ext.woff2') format('woff2');
38
+ font-weight: 100 1000;
39
+ font-style: normal;
40
+ font-display: swap;
41
+ unicode-range: U+0100-02AF, U+0304, U+0308, U+0329, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
42
+ }
43
+
44
+ * {
45
+ margin: 0;
46
+ padding: 0;
47
+ box-sizing: border-box;
48
+ }
49
+
50
+ html {
51
+ -webkit-print-color-adjust: exact;
52
+ print-color-adjust: exact;
53
+ }
54
+
55
+ body {
56
+ font-family: 'DM Sans', sans-serif;
57
+ font-size: 11px;
58
+ line-height: 1.5;
59
+ color: #1a1a2e;
60
+ background: #ffffff;
61
+ padding: 0;
62
+ margin: 0;
63
+ }
64
+
65
+ .page {
66
+ width: 100%;
67
+ max-width: {{PAGE_WIDTH}};
68
+ margin: 0 auto;
69
+ padding: 2px 0;
70
+ }
71
+
72
+ /* === HEADER === */
73
+ .header {
74
+ margin-bottom: 20px;
75
+ }
76
+
77
+ .header h1 {
78
+ font-family: 'Space Grotesk', sans-serif;
79
+ font-size: 28px;
80
+ font-weight: 700;
81
+ color: #1a1a2e;
82
+ letter-spacing: -0.02em;
83
+ margin-bottom: 6px;
84
+ line-height: 1.1;
85
+ }
86
+
87
+ .header-gradient {
88
+ height: 2px;
89
+ background: linear-gradient(to right, hsl(187, 74%, 32%), hsl(270, 70%, 45%));
90
+ border-radius: 1px;
91
+ margin-bottom: 10px;
92
+ }
93
+
94
+ .contact-row {
95
+ display: flex;
96
+ flex-wrap: wrap;
97
+ gap: 8px 14px;
98
+ font-family: 'DM Sans', sans-serif;
99
+ font-size: 10.5px;
100
+ line-height: 1.4;
101
+ color: #555;
102
+ }
103
+
104
+ .contact-row a {
105
+ color: #555;
106
+ text-decoration: none;
107
+ }
108
+
109
+ .contact-row .separator {
110
+ color: #ccc;
111
+ }
112
+
113
+ /* === SECTIONS === */
114
+ .section {
115
+ margin-bottom: 18px;
116
+ }
117
+
118
+ .section-title {
119
+ font-family: 'Space Grotesk', sans-serif;
120
+ font-size: 12px;
121
+ font-weight: 700;
122
+ text-transform: uppercase;
123
+ letter-spacing: 0.06em;
124
+ color: hsl(187, 74%, 32%);
125
+ border-bottom: 1.5px solid #e2e2e2;
126
+ padding-bottom: 4px;
127
+ margin-bottom: 10px;
128
+ line-height: 1.2;
129
+ }
130
+
131
+ /* === PROFESSIONAL SUMMARY === */
132
+ .summary-text {
133
+ font-size: 11px;
134
+ line-height: 1.7;
135
+ color: #2f2f2f;
136
+ }
137
+
138
+ /* Links must never break across lines */
139
+ a {
140
+ white-space: nowrap;
141
+ }
142
+
143
+ /* === CORE COMPETENCIES === */
144
+ .competencies-grid {
145
+ display: flex;
146
+ flex-wrap: wrap;
147
+ gap: 8px;
148
+ }
149
+
150
+ .competency-tag {
151
+ font-family: 'DM Sans', sans-serif;
152
+ font-size: 10px;
153
+ font-weight: 500;
154
+ color: hsl(187, 74%, 28%);
155
+ background: hsl(187, 40%, 95%);
156
+ padding: 4px 10px;
157
+ border-radius: 3px;
158
+ border: 1px solid hsl(187, 40%, 88%);
159
+ }
160
+
161
+ /* === WORK EXPERIENCE === */
162
+ .job {
163
+ margin-bottom: 14px;
164
+ }
165
+
166
+ .job-header {
167
+ display: flex;
168
+ justify-content: space-between;
169
+ align-items: baseline;
170
+ gap: 12px;
171
+ margin-bottom: 4px;
172
+ }
173
+
174
+ .job-company {
175
+ font-family: 'Space Grotesk', sans-serif;
176
+ font-size: 12.5px;
177
+ font-weight: 600;
178
+ color: hsl(270, 70%, 45%);
179
+ }
180
+
181
+ .job-period {
182
+ font-size: 10.5px;
183
+ color: #777;
184
+ white-space: nowrap;
185
+ }
186
+
187
+ .job-role {
188
+ font-size: 11px;
189
+ font-weight: 600;
190
+ color: #333;
191
+ margin-bottom: 6px;
192
+ }
193
+
194
+ .job-location {
195
+ font-size: 10px;
196
+ color: #888;
197
+ }
198
+
199
+ .job ul {
200
+ padding-left: 18px;
201
+ margin-top: 6px;
202
+ }
203
+
204
+ .job li {
205
+ font-size: 10.5px;
206
+ line-height: 1.6;
207
+ color: #333;
208
+ margin-bottom: 4px;
209
+ }
210
+
211
+ .job li strong {
212
+ font-weight: 600;
213
+ }
214
+
215
+ /* === PROJECTS === */
216
+ .project {
217
+ margin-bottom: 12px;
218
+ }
219
+
220
+ .project-title {
221
+ font-family: 'Space Grotesk', sans-serif;
222
+ font-size: 11.5px;
223
+ font-weight: 600;
224
+ color: hsl(270, 70%, 45%);
225
+ }
226
+
227
+ .project-badge {
228
+ font-size: 9px;
229
+ font-weight: 500;
230
+ color: hsl(187, 74%, 32%);
231
+ background: hsl(187, 40%, 95%);
232
+ padding: 1px 6px;
233
+ border-radius: 2px;
234
+ margin-left: 6px;
235
+ }
236
+
237
+ .project-desc {
238
+ font-size: 10.5px;
239
+ color: #444;
240
+ margin-top: 3px;
241
+ line-height: 1.55;
242
+ }
243
+
244
+ .project-tech {
245
+ font-size: 9.5px;
246
+ color: #888;
247
+ margin-top: 3px;
248
+ }
249
+
250
+ /* === EDUCATION === */
251
+ .edu-item {
252
+ margin-bottom: 8px;
253
+ }
254
+
255
+ .edu-header {
256
+ display: flex;
257
+ justify-content: space-between;
258
+ align-items: baseline;
259
+ gap: 12px;
260
+ }
261
+
262
+ .edu-title {
263
+ font-weight: 600;
264
+ font-size: 11px;
265
+ color: #333;
266
+ }
267
+
268
+ .edu-org {
269
+ color: hsl(270, 70%, 45%);
270
+ font-weight: 500;
271
+ }
272
+
273
+ .edu-year {
274
+ font-size: 10px;
275
+ color: #777;
276
+ white-space: nowrap;
277
+ }
278
+
279
+ .edu-desc {
280
+ font-size: 10px;
281
+ color: #666;
282
+ margin-top: 2px;
283
+ line-height: 1.5;
284
+ }
285
+
286
+ /* === CERTIFICATIONS === */
287
+ .cert-item {
288
+ display: grid;
289
+ grid-template-columns: minmax(0, 1fr) minmax(90px, max-content) 44px;
290
+ align-items: baseline;
291
+ gap: 12px;
292
+ margin-bottom: 6px;
293
+ }
294
+
295
+ .cert-title {
296
+ font-size: 10.5px;
297
+ font-weight: 500;
298
+ color: #333;
299
+ min-width: 0;
300
+ }
301
+
302
+ .cert-org {
303
+ color: hsl(270, 70%, 45%);
304
+ white-space: nowrap;
305
+ }
306
+
307
+ .cert-year {
308
+ font-size: 10px;
309
+ color: #777;
310
+ white-space: nowrap;
311
+ text-align: right;
312
+ }
313
+
314
+ /* === SKILLS === */
315
+ .skills-grid {
316
+ display: flex;
317
+ flex-wrap: wrap;
318
+ gap: 6px 14px;
319
+ }
320
+
321
+ .skill-item {
322
+ font-size: 10.5px;
323
+ color: #444;
324
+ }
325
+
326
+ .skill-category {
327
+ font-weight: 600;
328
+ color: #333;
329
+ font-size: 10.5px;
330
+ }
331
+
332
+ /* === PRINT === */
333
+ @media print {
334
+ body {
335
+ -webkit-print-color-adjust: exact;
336
+ print-color-adjust: exact;
337
+ }
338
+
339
+ .page {
340
+ padding: 0;
341
+ }
342
+ }
343
+
344
+ /* === PAGE BREAK CONTROL === */
345
+ .avoid-break,
346
+ .job,
347
+ .project,
348
+ .edu-item,
349
+ .cert-item {
350
+ break-inside: avoid;
351
+ page-break-inside: avoid;
352
+ }
353
+ </style>
354
+ </head>
355
+ <body>
356
+ <div class="page">
357
+
358
+ <!-- HEADER -->
359
+ <div class="header avoid-break">
360
+ <h1>{{NAME}}</h1>
361
+ <div class="header-gradient"></div>
362
+ <div class="contact-row">
363
+ <span>{{PHONE}}</span>
364
+ <span class="separator">|</span>
365
+ <span>{{EMAIL}}</span>
366
+ <span class="separator">|</span>
367
+ <a href="{{LINKEDIN_URL}}">{{LINKEDIN_DISPLAY}}</a>
368
+ <span class="separator">|</span>
369
+ <a href="{{PORTFOLIO_URL}}">{{PORTFOLIO_DISPLAY}}</a>
370
+ <span class="separator">|</span>
371
+ <span>{{LOCATION}}</span>
372
+ </div>
373
+ </div>
374
+
375
+ <!-- PROFESSIONAL SUMMARY -->
376
+ <div class="section avoid-break">
377
+ <div class="section-title">{{SECTION_SUMMARY}}</div>
378
+ <div class="summary-text">{{SUMMARY_TEXT}}</div>
379
+ </div>
380
+
381
+ <!-- CORE COMPETENCIES -->
382
+ <div class="section">
383
+ <div class="section-title">{{SECTION_COMPETENCIES}}</div>
384
+ <div class="competencies-grid">
385
+ {{COMPETENCIES}}
386
+ </div>
387
+ </div>
388
+
389
+ <!-- WORK EXPERIENCE -->
390
+ <div class="section">
391
+ <div class="section-title">{{SECTION_EXPERIENCE}}</div>
392
+ {{EXPERIENCE}}
393
+ </div>
394
+
395
+ <!-- PROJECTS -->
396
+ <div class="section avoid-break">
397
+ <div class="section-title">{{SECTION_PROJECTS}}</div>
398
+ {{PROJECTS}}
399
+ </div>
400
+
401
+ <!-- EDUCATION -->
402
+ <div class="section avoid-break">
403
+ <div class="section-title">{{SECTION_EDUCATION}}</div>
404
+ {{EDUCATION}}
405
+ </div>
406
+
407
+ <!-- CERTIFICATIONS -->
408
+ <div class="section avoid-break">
409
+ <div class="section-title">{{SECTION_CERTIFICATIONS}}</div>
410
+ {{CERTIFICATIONS}}
411
+ </div>
412
+
413
+ <!-- SKILLS -->
414
+ <div class="section avoid-break">
415
+ <div class="section-title">{{SECTION_SKILLS}}</div>
416
+ {{SKILLS}}
417
+ </div>
418
+
419
+ </div>
420
+ </body>
421
+ </html>
@@ -0,0 +1,123 @@
1
+ %-------------------------
2
+ % Career-Ops LaTeX CV Template
3
+ % Based on: Gabriel Sison / sb2nov resume template
4
+ % License: MIT
5
+ %------------------------
6
+
7
+ %%%%%%%%%%%%%%%%%%%%%%%%%%%% Random Stuff %%%%%%%%%%%%%%%%%%%%%%%%%%%%
8
+ \documentclass[letterpaper,11pt]{article}
9
+ \usepackage{latexsym}
10
+ \usepackage[empty]{fullpage}
11
+ \usepackage{titlesec}
12
+ \usepackage{marvosym}
13
+ \usepackage[usenames,dvipsnames]{color}
14
+ \usepackage{verbatim}
15
+ \usepackage{enumitem}
16
+ \usepackage[hidelinks]{hyperref}
17
+ \usepackage{fancyhdr}
18
+ \usepackage[english]{babel}
19
+ \usepackage{tabularx}
20
+ \usepackage{fontawesome}
21
+ \usepackage{multicol}
22
+ \setlength{\multicolsep}{-3.0pt}
23
+ \setlength{\columnsep}{-1pt}
24
+ \input{glyphtounicode}
25
+ \pagestyle{fancy}
26
+ \fancyhf{} % clear all header and footer fields
27
+ \fancyfoot{}
28
+ \renewcommand{\headrulewidth}{0pt}
29
+ \renewcommand{\footrulewidth}{0pt}
30
+ % Adjust margins
31
+ \addtolength{\oddsidemargin}{-0.6in}
32
+ \addtolength{\evensidemargin}{-0.5in}
33
+ \addtolength{\textwidth}{1.19in}
34
+ \addtolength{\topmargin}{-.7in}
35
+ \addtolength{\textheight}{1.4in}
36
+ \urlstyle{same}
37
+ \raggedbottom
38
+ \raggedright
39
+ \setlength{\tabcolsep}{0in}
40
+ % Sections formatting
41
+ \titleformat{\section}{
42
+ \vspace{-7pt}\scshape\raggedright\large\bfseries
43
+ }{}{0em}{}[\color{black}\titlerule \vspace{0pt}]
44
+ % Ensure that generate pdf is machine readable/ATS parsable
45
+ \pdfgentounicode=1
46
+
47
+ %%%%%%%%%%%%%%%%%%%%%%%%%%%% Commands %%%%%%%%%%%%%%%%%%%%%%%%%%%%
48
+ \newcommand{\resumeItem}[1]{
49
+ \item\small{
50
+ {#1 \vspace{-3pt}}
51
+ }
52
+ }
53
+ \newcommand{\resumeSubheading}[4]{
54
+ \vspace{-3pt}\item
55
+ \begin{tabular*}{1.0\textwidth}[t]{l@{\extracolsep{\fill}}r}
56
+ \textbf{#1} & \textbf{\small #2} \\
57
+ \textit{\small#3} & \textit{\small #4} \\
58
+ \end{tabular*}\vspace{-7pt}
59
+ }
60
+ \newcommand{\resumeSubheadingContinue}[2]{
61
+ \vspace{-3pt}
62
+ \begin{tabular*}{1.0\textwidth}[t]{l@{\extracolsep{\fill}}r}
63
+ \textit{\small#1} & \textit{\small #2} \\
64
+ \end{tabular*}\vspace{-7pt}
65
+ }
66
+ \newcommand{\resumeProjectHeading}[2]{
67
+ \vspace{-3pt}\item
68
+ \begin{tabular*}{1.0\textwidth}[t]{l@{\extracolsep{\fill}}r}
69
+ \textbf{#1} & \textbf{\small #2} \\
70
+ \end{tabular*}\vspace{-7pt}
71
+ }
72
+ \newcommand{\resumeSubItem}[1]{\resumeItem{#1}\vspace{0pt}}
73
+ \renewcommand\labelitemi{$\vcenter{\hbox{\tiny$\bullet$}}$}
74
+ \renewcommand\labelitemii{$\vcenter{\hbox{\tiny$\bullet$}}$}
75
+ \newcommand{\resumeSubHeadingListStart}{\begin{itemize}[leftmargin=0.0in, label={}]}
76
+ \newcommand{\resumeSubHeadingListEnd}{\end{itemize}}
77
+ \newcommand{\resumeItemListStart}{\begin{itemize}}
78
+ \newcommand{\resumeItemListEnd}{\end{itemize}\vspace{0pt}}
79
+
80
+ %%%%%%%%%%%%%%%%%%%%%%%%%%%% Heading %%%%%%%%%%%%%%%%%%%%%%%%%%%%
81
+ \begin{document}
82
+ \begin{center}
83
+ % NAME
84
+ {\Huge\scshape {{NAME}}}
85
+ % SUBHEADING
86
+ \\ {{CONTACT_LINE}}\\
87
+ \small
88
+ % EMAIL
89
+ \href{mailto:{{EMAIL_URL}}}{\raisebox{-0.2\height}\faEnvelope\ \underline{{{EMAIL_DISPLAY}}}} ~
90
+ % LINKEDIN
91
+ \href{{{LINKEDIN_URL}}}{\raisebox{-0.2\height}\faLinkedin\ \underline{{{LINKEDIN_DISPLAY}}}} ~
92
+ % GITHUB
93
+ \href{{{GITHUB_URL}}}{\raisebox{-0.2\height}\faGithub\ \underline{{{GITHUB_DISPLAY}}}}
94
+ \end{center}
95
+
96
+ %%%%%%%%%%%%%%%%%%%%%%%%%%%% Education %%%%%%%%%%%%%%%%%%%%%%%%%%%%
97
+ \section{Education}
98
+ \resumeSubHeadingListStart
99
+ {{EDUCATION}}
100
+ \resumeSubHeadingListEnd
101
+
102
+ %%%%%%%%%%%%%%%%%%%%%%%%%%%% Experience %%%%%%%%%%%%%%%%%%%%%%%%%%%%
103
+ \section{Work Experience}
104
+ \resumeSubHeadingListStart
105
+ {{EXPERIENCE}}
106
+ \resumeSubHeadingListEnd
107
+
108
+ %%%%%%%%%%%%%%%%%%%%%%%%%%%% PROJECTS %%%%%%%%%%%%%%%%%%%%%%%%%%%%
109
+ \section{Personal Projects}
110
+ \resumeSubHeadingListStart
111
+ {{PROJECTS}}
112
+ \resumeSubHeadingListEnd
113
+
114
+ %%%%%%%%%%%%%%%%%%%%%%%%%%%% Technical Skills %%%%%%%%%%%%%%%%%%%%%%%%%%%%
115
+ \section{Technical Skills}
116
+ \vspace{-7pt}
117
+ \begin{itemize}
118
+ [leftmargin=0.15in, label={}]\small{\item{
119
+ {{SKILLS}}
120
+ }}
121
+ \end{itemize}
122
+
123
+ \end{document}